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