▌第一次閱讀本系列的,可以先看:


▌第一次閱讀垃圾回收器系列,可以先看:


▌提要:

到目前為止有三個主要函數。
void free_all_register_address(void);               // 釋放
void register_address(void *address);               // 標記
void new_1d(void **ptr, int length, int type_side); // 分配
分別負責 釋放標記分配 這三個部分。
它們可以構成最基礎需求,但這並不足夠。
我們需要加入更多的功能,去滿足更多的需求。

▌有什麼功能可加入/完善?

先想一下使用者(程式員)還有什麼需求。
  1. 手動釋放 —— free()
  2. 改變分配後的空間大小。 —— realloc()

▌手動釋放:

透過 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 early_free(void *address) {
 deregist_address(address);
 free(address);
}
代碼很短,就是 釋放 和 註銷。(次序不影響)

▌改變分配後的空間大小:

以上同理,如果自行調用 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;  //取得中轉指標的地址
}
分配後地址不相同,就註銷 地址,註冊 地址。

▌用法:

int *ptr = NULL;
new_1d(&ptr, 5, sizeof(int));
re_1d(&ptr, 10, sizeof(int));
early_free(ptr);

▌明白的,自然會明白。

(`・ω・´)