From Unix某論壇,忘記名字了...但這段文字從宏觀上講清楚了Linux Memory的構(gòu)架。
1. 內(nèi)核初始化:
* 內(nèi)核建立好內(nèi)核頁目錄頁表數(shù)據(jù)庫,假設(shè)物理內(nèi)存大小為len,則建立了[3G--3G+len]::[0--len]這樣的虛地址vaddr和物理地址paddr的線性對應(yīng)關(guān)系;
* 內(nèi)核建立一個page數(shù)組,page數(shù)組和物理頁面系列完全是線性對應(yīng),page用來管理該物理頁面狀態(tài),每個物理頁面的虛地址保存在page->virtual中;
* 內(nèi)核建立好一個free_list,將沒有使用的物理頁面對應(yīng)的page放入其中,已經(jīng)使用的就不用放入了;
2. 內(nèi)核模塊申請內(nèi)存vaddr = get_free_pages(mask,order):
* 內(nèi)存管理模塊從free_list找到一個page,將page->virtual作為返回值,該返回值就是對應(yīng)物理頁面的虛地址;
* 將page從free_list中脫離;
* 模塊使用該虛擬地址操作對應(yīng)的物理內(nèi)存;
3. 內(nèi)核模塊使用vaddr,例如執(zhí)行指令mov(eax, vaddr):
* CPU獲得vaddr這個虛地址,利用建立好的頁目錄頁表數(shù)據(jù)庫,找到其對應(yīng)的物理內(nèi)存地址;
* 將eax的內(nèi)容寫入vaddr對應(yīng)的物理內(nèi)存地址內(nèi);
4. 內(nèi)核模塊釋放內(nèi)存free_pages(vaddr,order):
* 依據(jù)vaddr找到對應(yīng)的page;
* 將該page加入到free_list中;
5. 用戶進程申請內(nèi)存vaddr = malloc(size):
* 內(nèi)存管理模塊從用戶進程內(nèi)存空間(0--3G)中找到一塊還沒使用的空間vm_area_struct(start--end);
* 隨后將其插入到task->mm->mmap鏈表中;
6. 用戶進程寫入vaddr(0-3G),例如執(zhí)行指令mov(eax, vaddr):
* CPU獲得vaddr這個虛地址,該虛地址應(yīng)該已經(jīng)由glibc庫設(shè)置好了,一定在3G一下的某個區(qū)域,根據(jù)CR3寄存器指向的current->pgd查當(dāng)前進程的頁目錄頁表數(shù)據(jù)庫,發(fā)現(xiàn)該vaddr對應(yīng)的頁目錄表項為0,故產(chǎn)生異常;
* 在異常處理中,發(fā)現(xiàn)該vaddr對應(yīng)的vm_area_struct已經(jīng)存在,為vaddr對應(yīng)的頁目錄表項分配一個頁表;
* 隨后從free_list找到一個page,將該page對應(yīng)的物理頁面物理首地址賦給vaddr對應(yīng)的頁表表項,很明顯,此時的vaddr和paddr不是線性對應(yīng)關(guān)系了;
* 將page從free_list中脫離;
* 異常處理返回;
* CPU重新執(zhí)行剛剛發(fā)生異常的指令mov(eax, vaddr);
* CPU獲得vaddr這個虛地址,根據(jù)CR3寄存器指向的current->pgd,利用建立好的頁目錄頁表數(shù)據(jù)庫,找到其對應(yīng)的物理內(nèi)存地址;
* 將eax的內(nèi)容寫入vaddr對應(yīng)的物理內(nèi)存地址內(nèi);
7. 用戶進程釋放內(nèi)存vaddr,free(vaddr):
* 找到該vaddr所在的vm_area_struct;
* 找到vm_area_struct:start--end對應(yīng)的所有頁目錄頁表項,清空對應(yīng)的所有頁表項;
* 釋放這些頁表項指向物理頁面所對應(yīng)的page,并將這些page加入到free_list隊列中;
* 有必要還會清空一些頁目錄表項,并釋放這些頁目錄表項指向的頁表;
* 從task->mm->mmap鏈中刪除該vm_area_struct并釋放掉;
綜合說明:
* 可用物理內(nèi)存就是free_list中各page對應(yīng)的物理內(nèi)存;
* 頁目錄頁表數(shù)據(jù)庫的主要目的是為CPU訪問物理內(nèi)存時轉(zhuǎn)換vaddr-->paddr使用,分配以及釋放內(nèi)存時不會用到,但是需要內(nèi)核內(nèi)存管理系統(tǒng)在合適時機為CPU建立好該庫;
* 對于用戶進程在6中獲得的物理頁面,有兩個頁表項對應(yīng),一個就是內(nèi)核頁目錄頁表數(shù)據(jù)庫的某個pte[i ],一個就是當(dāng)前進程內(nèi)核頁目錄頁表數(shù)據(jù)庫的某個 pte[j],但是只有一個page和其對應(yīng)。如果此時調(diào)度到其他進程,其他進程申請并訪問某個內(nèi)存,則不會涉及到該物理頁面,因為其分配時首先要從 free_list中找一個page,而該物理頁面對應(yīng)的page已經(jīng)從free_list中脫離出來了,因此不存在該物理頁面被其他進程改寫操作的情況。內(nèi)核中通過get_free_pages等方式獲取內(nèi)存時,也不會涉及到該物理頁面,原理同前所述。