對指標、地址不熟悉的:
Days 3: 重溫指標:記憶體地址 、 儲存空間 至
Days 7: 重溫指標:數據、數據類型的本質
而 Days 8: 重溫指標:雜項:指標宣告、運算符 是基礎知識及雜項,不看不影響本系列閱讀。
對如何動態分配記憶體( malloc, calloc, realloc, free )不熟悉的:
Days 9: 動態記憶體分配:malloc()、calloc()、realloc()、free(),內存洩露
不知道什麼是 atexit() 的:
Days 10: atexit()、函數程序結束時調用函數
不知道什麼是 垃圾回收器 的:
Days 11: 什麼是垃圾回收器?
其實還有一點點知識點沒有包括,
不過已經可以開始嘗試實現垃圾回收器~!
今天只是粗略實現,之後再具體實現,
首先,正常的做法是怎樣?
int *ptr = (int*)malloc(10 * sizeof(int));
free(ptr);
我們想要怎樣?
int *ptr = (int*)malloc(10 * sizeof(int));
簡單來講,就是想要 分配記憶體後不需要理會釋放的問題。
即是 自動的記憶體管理。
現在我們手上有一個很有趣的材料:
atexit();
可以在 主程序結束時調用函數。
int *ptr = (int*)malloc(10 * sizeof(int));
atexit(free(ptr));
咳咳,當然不能這樣, atexit() 不能接受有參數的函數,
同時 函數地址 也不能帶有默認參數。
但是方向很正確。
我們需要一個 沒有參數也沒有回傳 的函數,
放入 atexit() 中註冊,使該函數在主程序結束時調用,
進行 free() 的工作。
void a_function_for_atexit_to_register(void){
//somethings to free()
}
而它能夠知道或紀錄著, (【標記-清除】)
曾經分配的記憶體空間的地址。
然後遍歷去釋放。 (【標記-清除】)
這正是 【標記-清除】 的概念。
而這個函數負責釋放的部分。
這個函數能夠知道 曾經分配的記憶體空間的地址,
但它不能存在參數,所以無法傳入地址進行紀錄,
代表會有 另一個函數 用於進行 地址的紀錄。
void a_function_for_register_address(void *address){
//save the address
}
我們還要用一個新的函數去取代 malloc(),有兩種形式:
void *my_malloc(int size);
void my_malloc(void **ptr, int size, int type_side);
個人偏好第二種形式,
原因可參看 Days 4: 重溫指標:靜態變數的地址、函數回傳地址 的最後,
以及 Days 9: 動態記憶體分配:malloc()、calloc()、realloc()、free(),內存洩露
內存洩漏的部分。
void my_malloc(void **ptr, int size, int type_side){
/*分配記憶體*/
*ptr = malloc(size * type_side);
/*紀錄地址*/
a_function_for_register_address(*ptr);
/*註冊 atexit() */
/*僅在程序第一次執行時呼叫 atexit() */
static int first_process = 1;
if (first_process) {
atexit(&a_function_for_atexit_to_register); //此函數只會被呼叫一次
first_process = 0; //第一次執行的標記
}
}
分三個部分,
第一,分配記憶體。
第二,紀錄 已經分配的記憶體空間 的地址。
第三,用 atexit() 進行註冊,僅一次。
現在我們手上有以下函數:
void a_function_for_atexit_to_register(void);
void a_function_for_register_address(void *address);
void my_malloc(void **ptr, int size, int type_side);
改個漂亮一點的名字,按個人習慣吧,
void free_all_register_address(void);
void register_address(void *address);
void new_1d(void **ptr, int length, int type_side);