iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 12
0
自我挑戰組

30 Days 如何把 C 語言偽裝成高階語言 OWO /系列 第 12

Days 12: 垃圾回收器系列:概念、粗略實現

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

本系列的大綱 傳送門


▌閱讀本文章的垃圾回收器系列前:

對指標、地址不熟悉的:
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(),內存洩露
內存洩漏的部分。


▌粗略估計 my_malloc() 的實現:

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);

目前還是很粗糙,不過...


篇幅太長不方便閱讀,下一篇繼續完善。


上一篇
Days 11: 什麼是垃圾回收器?
下一篇
Days 13: 垃圾回收器系列:完善 用於標記地址的函數
系列文
30 Days 如何把 C 語言偽裝成高階語言 OWO /31

尚未有邦友留言

立即登入留言