(Minix 3.1.0)
Minix 3 不支持頁(yè)式存儲(chǔ),進(jìn)程在整個(gè)執(zhí)行過(guò)程中,所占用內(nèi)存的大小和位置不會(huì)變化。
它的內(nèi)存管理工作,主要是:
1.調(diào)用 fork() 創(chuàng)建新進(jìn)程時(shí),為新進(jìn)程申請(qǐng)內(nèi)存;
2.調(diào)用 exec() 等更換內(nèi)存鏡像時(shí),釋放舊鏡像占用的內(nèi)存,為新鏡像申請(qǐng)內(nèi)存(先釋放,后申請(qǐng));
3.進(jìn)程結(jié)束(不管是自己退出,還是被殺死)時(shí),釋放其所占用的內(nèi)存;
4.系統(tǒng)初始化時(shí),系統(tǒng)進(jìn)程申請(qǐng)內(nèi)存。
下面不考慮系統(tǒng)初始化時(shí)的內(nèi)存管理工作。
在 Minix 3 中,由進(jìn)程管理器PM管理內(nèi)存。
Minix 3 中的程序可以被編譯為指令和數(shù)據(jù)不分離的形式,此時(shí)一個(gè)進(jìn)程的正文,數(shù)據(jù),堆棧共用一塊作為一個(gè)整體申請(qǐng)或釋放的內(nèi)存;
也可以被編譯為指令和數(shù)據(jù)分離的形式,兩部分占用的內(nèi)存分別管理。
指令和數(shù)據(jù)分離的好處在于可以通過(guò)共享正文來(lái)節(jié)約內(nèi)存:
1.當(dāng)一個(gè)進(jìn)程調(diào)用 fork() 來(lái)創(chuàng)建新進(jìn)程時(shí),只需要為新進(jìn)程的數(shù)據(jù)和堆棧申請(qǐng)內(nèi)存,而正文可以共享。
2.當(dāng)一個(gè)進(jìn)程調(diào)用 exec() 等更換內(nèi)存鏡像時(shí),系統(tǒng)進(jìn)程表會(huì)被搜索,以確定需要的正文是否已經(jīng)由其它進(jìn)程載入內(nèi)存,
若已經(jīng)載入,則該正文被共享,就只需為新鏡像的數(shù)據(jù)和堆棧申請(qǐng)內(nèi)存。
3.進(jìn)程結(jié)束時(shí),它的數(shù)據(jù)和堆棧所占用的內(nèi)存會(huì)被釋放,而正文所占用的內(nèi)存,只有在該正文沒(méi)有被其它進(jìn)程共享時(shí)才會(huì)釋放。
Minix 3 雖不支持頁(yè)式存儲(chǔ),但是提供一些用于交換的函數(shù),由文件
/include/minix/config.h 中的宏 ENABLE_SWAP 決定是否編譯進(jìn)系統(tǒng)。
進(jìn)程管理器PM管理內(nèi)存的主要數(shù)據(jù)結(jié)構(gòu)為 struct hole,
見(jiàn) /servers/pm/alloc.c :
PRIVATE struct hole {
struct hole *h_next; /* pointer to next entry on the list */
phys_clicks h_base; /* where does the hole begin? */
phys_clicks h_len; /* how big is the hole? */
} hole[ NR_HOLES ];
使用單鏈表,按內(nèi)存地址由低到高記錄內(nèi)存塊。注意,進(jìn)程中數(shù)據(jù)和堆棧間的空隙被認(rèn)為已經(jīng)分配給了進(jìn)程,而不被記錄。
鏈表節(jié)點(diǎn)所占用的內(nèi)存,不是動(dòng)態(tài)申請(qǐng)釋放的,而是定義了數(shù)組 hole,為鏈表節(jié)點(diǎn)提供內(nèi)存。
見(jiàn)該文件接下來(lái)的定義,
PRIVATE struct hole *hole_head; /* pointer to first hole */
PRIVATE struct hole *free_slots; /* ptr to list of unused table slots */
hole_head 一個(gè)單鏈表頭指針,此鏈表用于維護(hù)尚未分配的內(nèi)存塊,按內(nèi)存塊地址由低到高記錄。
free_slots 一個(gè)單鏈表頭指針,此鏈表用于維護(hù)數(shù)組 hole 中尚未被 hole_head 使用的節(jié)點(diǎn)。
mem_init() 對(duì)內(nèi)存管理的相關(guān)數(shù)據(jù)進(jìn)行初始化。
文件 /servers/pm/main.c 中的 main() 以適當(dāng)?shù)膮?shù)調(diào)用 mem_init() 完成內(nèi)存管理的初始化。
alloc_mem() 申請(qǐng)內(nèi)存。
當(dāng)申請(qǐng)一定大小的內(nèi)存時(shí),遍歷鏈表 hole_head ,直至找到足夠大的內(nèi)存塊,從中剪切出所需大小。
即首次適應(yīng)算法。
free_mem() 釋放內(nèi)存。
與 alloc_mem() 功能相反,而且釋放內(nèi)存后,還會(huì)調(diào)用 merge() 合并相鄰的內(nèi)存塊。
merge() 合并連續(xù)的未分配內(nèi)存塊。
本來(lái)連續(xù)的內(nèi)存,經(jīng)過(guò)若干次內(nèi)存申請(qǐng)與釋放后,可能被切成多塊,由鏈表 hole_head 中的多個(gè)節(jié)點(diǎn)記錄,
每次釋放內(nèi)存后調(diào)用 merge() 以避免此情況出現(xiàn)。
del_slot() 將一個(gè)鏈表節(jié)點(diǎn)從 hole_head 中刪除,移入 free_slots 。
因?yàn)殒湵?hole_head 中的節(jié)點(diǎn)所占用的內(nèi)存不是動(dòng)態(tài)申請(qǐng)釋放的,而是定義了數(shù)組,
需要新節(jié)點(diǎn)時(shí),就從數(shù)組中取,所以需要一些相關(guān)的維護(hù)工作。