▌第一次閱讀本系列的,可以先看:
▌第一次閱讀垃圾回收器系列,可以先看:
▌提要:
到目前為止有三個主要函數。
void free_all_register_address(void); // 釋放
void register_address(void *address); // 標記
void new_1d(void **ptr, int length, int type_side); // 分配
分別負責 釋放、標記、分配 這三個部分。
它們可以構成最基礎的需求,但這並不足夠。
我們需要加入更多的功能,去滿足更多的需求。
void free_all_register_address(void); // 釋放
void register_address(void *address); // 標記
void new_1d(void **ptr, int length, int type_side); // 分配
我們需要加入更多的功能,去滿足更多的需求。
▌有什麼功能可加入/完善?
先想一下使用者(程式員)還有什麼需求。
- 手動釋放 —— free()
- 改變分配後的空間大小。 —— realloc()
▌手動釋放:
透過 new_1d
分配後,地址被記錄並在程式結束後自動釋放,
若果自行加入 free()
,被記錄地址依舊會在結束後再次被釋放,
觸發雙重釋放的問題。
所以我們需要在手動釋放時,在 address_pool
中刪除被記錄地址。
即 register_address
的相反行為 —— 註銷地址。
new_1d
分配後,地址被記錄並在程式結束後自動釋放,若果自行加入
free()
,被記錄地址依舊會在結束後再次被釋放,觸發雙重釋放的問題。
address_pool
中刪除被記錄地址。即
register_address
的相反行為 —— 註銷地址。▌以下註銷地址的實作:
void deregist_address(void *address) {
/*用於取得記憶體地址池的資料*/
void ***address_pool = NULL;
int *index;
/*取得記憶體地址池的資料*/
connect_address_pool(&address_pool, &index);
/*遍歷 address_pool 的空間*/
for (int i = 0; i < *index; i++) {
/*具體註銷工作*/
if ((*address_pool)[i] == address) { //尋找對應的記憶體地址
(*address_pool)[i] = NULL; //註銷註冊
break; //減少迴圈開支
}
}
}
如果之前的文章都有看的話,絕對會明白,不廢話了。
void deregist_address(void *address) {
/*用於取得記憶體地址池的資料*/
void ***address_pool = NULL;
int *index;
/*取得記憶體地址池的資料*/
connect_address_pool(&address_pool, &index);
/*遍歷 address_pool 的空間*/
for (int i = 0; i < *index; i++) {
/*具體註銷工作*/
if ((*address_pool)[i] == address) { //尋找對應的記憶體地址
(*address_pool)[i] = NULL; //註銷註冊
break; //減少迴圈開支
}
}
}
▌以下手動釋放的實作:
void early_free(void *address) {
deregist_address(address);
free(address);
}
代碼很短,就是 釋放 和 註銷。(次序不影響)
void early_free(void *address) {
deregist_address(address);
free(address);
}
▌改變分配後的空間大小:
以上同理,如果自行調用 realloc()
去改變空間大小,
返回的地址若果不相同,會同時造成 內存洩漏 及 雙重釋放 。
洩漏了新地址,雙重釋放了舊地址。
realloc()
去改變空間大小,返回的地址若果不相同,會同時造成 內存洩漏 及 雙重釋放 。
▌以下實作:
void re_1d(void **ptr, int length, int type_side){
/*重新分配記憶體*/
void *temp_ptr = NULL; //中轉指標
temp_ptr = realloc(*ptr, length * type_side);
/*對realloc分配記憶體的錯誤檢測*/
if (temp_ptr == NULL) { //內存不足,記憶體分配失敗
/*錯誤處理*/
}
/*分配後地址不相同*/
if (temp_ptr != *ptr) {
deregist_address(*ptr); //註銷註冊
register_address(temp_ptr); //重新登記
}
/*成功建立的空間分配給ptr*/
*ptr = temp_ptr; //取得中轉指標的地址
}
分配後地址不相同,就註銷 舊地址,註冊 新地址。
void re_1d(void **ptr, int length, int type_side){
/*重新分配記憶體*/
void *temp_ptr = NULL; //中轉指標
temp_ptr = realloc(*ptr, length * type_side);
/*對realloc分配記憶體的錯誤檢測*/
if (temp_ptr == NULL) { //內存不足,記憶體分配失敗
/*錯誤處理*/
}
/*分配後地址不相同*/
if (temp_ptr != *ptr) {
deregist_address(*ptr); //註銷註冊
register_address(temp_ptr); //重新登記
}
/*成功建立的空間分配給ptr*/
*ptr = temp_ptr; //取得中轉指標的地址
}
▌用法:
int *ptr = NULL;
new_1d(&ptr, 5, sizeof(int));
re_1d(&ptr, 10, sizeof(int));
early_free(ptr);
int *ptr = NULL;
new_1d(&ptr, 5, sizeof(int));
re_1d(&ptr, 10, sizeof(int));
early_free(ptr);
0 Comments
發佈留言