1 名詞解釋:
(1)頁(yè)框:物理內(nèi)存的描述,必須牢牢記住,頁(yè)框就是物理內(nèi)存
(2)頁(yè)描述符:描述每一個(gè)頁(yè)框的狀態(tài)信息,所有的也描述符都保存在mem_map[ ]數(shù)組中,每個(gè)描述符32個(gè)字節(jié)
(3)節(jié)點(diǎn):系統(tǒng)物理內(nèi)存被劃分為多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)內(nèi)cpu訪問頁(yè)面的時(shí)間是相同的,對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu):節(jié)點(diǎn)描述符
(4)管理區(qū):每個(gè)節(jié)點(diǎn)又分為多個(gè)管理區(qū) 對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu): 管理區(qū)描述符
2 頁(yè)表管理
重點(diǎn)介紹內(nèi)核頁(yè)表的管理,主要分為兩個(gè)階段:?jiǎn)?dòng)階段映射8M的頁(yè)表和剩余頁(yè)表的映射階段
(1)啟動(dòng)階段8M頁(yè)表的映射過程
(2)剩余頁(yè)表的映射過程
幾個(gè)比較重要的地址轉(zhuǎn)換:
虛擬地址轉(zhuǎn)換成物理地址: virt_to_phsy(address){ __pa(address) }
虛擬地址轉(zhuǎn)換頁(yè)描述符的地址: virt_to_page( kaddr ) { return mem_map + __pa(kaddr) >>12 }
3 用戶進(jìn)程的地址空間
從內(nèi)核看來(lái),整個(gè)4G的地址空間是這樣的。
進(jìn)程可用的地址空間是被一個(gè)叫mm_struct(進(jìn)程地址空間描述符)結(jié)構(gòu)體來(lái)管理的,同一個(gè)進(jìn)程內(nèi)的多個(gè)線程是共享這個(gè)數(shù)據(jù)結(jié)構(gòu)的。
同時(shí),對(duì)于用戶進(jìn)程來(lái)說,每一個(gè)進(jìn)程有一個(gè)獨(dú)一無(wú)二的mm_struct,但是內(nèi)核線程確不是必須的。下面是操作mm_struct的一些函數(shù)。
當(dāng)然如果在進(jìn)程創(chuàng)建的時(shí)候指定子進(jìn)程共享父進(jìn)程的虛擬地址空間的話,比如:
if ( clone_flags & CLONE_VM )
{
atomic_inc(&old_mm->mm_user)
mm = &oldmm;
goto good_mm;
}
還有一點(diǎn)許喲阿注意的就是系統(tǒng)中的第一個(gè)mm_struct是需要靜態(tài)初始化的,以后的所有的mm_strcut都是通過拷貝生成的。
mmap函數(shù),內(nèi)存映射函數(shù)
該函數(shù)的主要功能是在進(jìn)程地址空間中創(chuàng)建一個(gè)線性區(qū)。有兩種類型的內(nèi)存映射:共享型和私有型。二者的主要區(qū)別可以理解成是否對(duì)其他進(jìn)程可見。共享型每次對(duì)線性區(qū)的讀寫都會(huì)修改
磁盤文件,一個(gè)進(jìn)程修改共享型的線性區(qū),其他映射這一線性區(qū)的所有進(jìn)程都是可見的。與內(nèi)存映射相關(guān)的數(shù)據(jù)結(jié)構(gòu):
(1)與所映射的文件相關(guān)的索引節(jié)點(diǎn)對(duì)象
(2)所映射文件的address_space對(duì)象
(3)不同進(jìn)程對(duì)同一文件進(jìn)行不同映射所使用的文件對(duì)象
(4)對(duì)文件進(jìn)行每一不同映射所使用的vm_area_struct
(5)對(duì)文件進(jìn)行映射的線性區(qū)所分配的每個(gè)頁(yè)框?qū)?yīng)的描述符
從圖上能看出一個(gè)文件對(duì)應(yīng)一個(gè)inode,對(duì)應(yīng)一個(gè)address_space,對(duì)應(yīng)多個(gè)struct file, 對(duì)應(yīng)多個(gè)vm_area_file ,對(duì)應(yīng)多個(gè)page(頁(yè)框),當(dāng)然也對(duì)應(yīng)多個(gè)page(頁(yè)描述符)、
mm_struct 內(nèi)存描述符中的兩棵樹: 當(dāng)前進(jìn)程內(nèi)所有線性區(qū)的一個(gè)鏈表和所有線性區(qū)的紅黑樹
mmap和mm_rb都可以訪問線性區(qū)。事實(shí)上,它們都指向了同一個(gè)vm_area_struct結(jié)構(gòu),只是鏈接的方式不同
mmap指向的線性區(qū)鏈表用來(lái)遍歷整個(gè)進(jìn)程的地址空間
紅黑樹mm_rb用來(lái)定位一個(gè)給定的線性地址落在進(jìn)程地址空間中的哪一個(gè)線性區(qū)中
另外,mmap_cache用來(lái)緩存最近用過的線性區(qū)
address_space中的兩棵樹:基數(shù)和優(yōu)先級(jí)搜索數(shù)。
address_space的page_tree指向了組織構(gòu)成這個(gè)文件的所有的頁(yè)描述符的基樹
address_space的i_mmap指向了組織構(gòu)成這個(gè)文件的所有的線性區(qū)描述符的基樹
要注意一個(gè)問題:
(1)共享內(nèi)存映射的頁(yè)通常保存在也高速緩存中,私有內(nèi)存映射的頁(yè)只要還沒有修改,也保存在頁(yè)高速緩存中。當(dāng)進(jìn)程試圖修改一個(gè)私有映射的頁(yè)時(shí),內(nèi)核 就把該頁(yè)框進(jìn)行復(fù)制,并在進(jìn)程頁(yè)表中用復(fù)制的頁(yè)替換原來(lái)的頁(yè),這就是寫時(shí)復(fù)制的基礎(chǔ)。復(fù)制后的頁(yè)框就不會(huì)放在頁(yè)告訴緩存中了,原因是它不再是表示磁盤上那 個(gè)文件的有效數(shù)據(jù)。
(2)線性區(qū)的開始和結(jié)束地址都是4K對(duì)齊的
進(jìn)程獲得新線性區(qū)的一些典型情況 :
剛剛創(chuàng)建的新進(jìn)程
使用exec系統(tǒng)調(diào)用裝載一個(gè)新的程序運(yùn)行
將一個(gè)文件(或部分)映射到進(jìn)程地址空間中
當(dāng)用戶堆棧不夠用的時(shí)候,擴(kuò)展堆棧對(duì)應(yīng)的線性區(qū)
創(chuàng)建內(nèi)存映射:
要想創(chuàng)建一個(gè)映射,就要調(diào)用mmap, mmap()最終會(huì)調(diào)用do_mmap()
static inline unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flag,unsigned long offset)
file:要映射的文件描述符,知道映射哪個(gè)文件才行
offset:文件內(nèi)的偏移量,指定要映射文件的一部分,當(dāng)然也可以是全部
len: 要映射文件的那一部分的長(zhǎng)度
flag:一組標(biāo)志,顯示的指定映射的那部分是MAP_SHARED或MAP_PRIVATE
prot: 一組權(quán)限,指定對(duì)線性區(qū)訪問的一種或多種訪問權(quán)限
addr: 一個(gè)可選的線性地址,表示從這個(gè)地址之后的某個(gè)位置創(chuàng)建線性區(qū)
基本的過程是:
(1)先為要映射的文件申請(qǐng)一段線性區(qū),調(diào)用內(nèi)存描述符的get_unmapped_area()
(2)做一些權(quán)限和標(biāo)志位檢查
(3)將文件對(duì)象的地址struct file地址賦值給線性區(qū)描述符vm_area_struct.vm_file
(4)調(diào)用mmap方法,這個(gè)方法最后調(diào)用generic_file_mmap()
其他線性區(qū)處理函數(shù)
(1)find_vma() : 查找一個(gè)線性地址所屬的線性區(qū)或后繼線性區(qū)
(2)find_vmm_interrection(): 查找一個(gè)與給定區(qū)間重疊的線性區(qū)
(3)get_unmapped_area() : 查找一個(gè)空閑的線性區(qū)
(4)insert_vm_struct () : 向進(jìn)程的內(nèi)存描述符中插入一個(gè)線性區(qū)
缺頁(yè)異常處理程序
(1)背景知識(shí)
內(nèi)核中的函數(shù)以直接了當(dāng)?shù)姆绞将@得動(dòng)態(tài)內(nèi)存,內(nèi)核是操作系統(tǒng)中優(yōu)先級(jí)最高的成分,內(nèi)核信任自己,采用面級(jí)內(nèi)存分配和小內(nèi)存分配以及非連續(xù)線性區(qū)得到內(nèi)存
用戶態(tài)進(jìn)程分配內(nèi)存時(shí),請(qǐng)求被認(rèn)為是不緊迫的,用戶進(jìn)程不可信任,因此,當(dāng)用戶態(tài)進(jìn)程請(qǐng)求動(dòng)態(tài)內(nèi)存時(shí),并沒有立即獲得實(shí)際的物理頁(yè)框,而僅僅獲得對(duì)一個(gè)
新的線性地址區(qū)間的使用權(quán)這個(gè)線性地址區(qū)間會(huì)成為進(jìn)程地址空間的一部分,稱作線性區(qū)(memory areas)。 這樣,當(dāng)用戶進(jìn)程真正向這些線性區(qū)寫的時(shí)候,就會(huì)
產(chǎn)生缺頁(yè)異常,在缺頁(yè)異常處理程序中獲得真正的物理內(nèi)存。
(2)缺頁(yè)異常處理程序需要區(qū)分引起缺頁(yè)的兩種情況:編程錯(cuò)引起的缺頁(yè)和屬于進(jìn)程的地址空間尚未分配到物理頁(yè)框
簡(jiǎn)單流程圖:
詳細(xì)流程圖:
linux為什么要分為三個(gè)區(qū):ZONE_DMA ZONE_NORMAL ZONE_HIGHMEM?
(1)isa總線的歷史遺留問題,只能訪問內(nèi)存的前16M的空間
(2)大容量的RAM使得線性地址空間太小,并不是所有的物理空間都能映射到唯一的線性地址空間
如何確定某個(gè)頁(yè)框?qū)儆谀膫€(gè)節(jié)點(diǎn)或管理區(qū)?
是由每個(gè)頁(yè)框描述符中的flag的高位索引的,比如page_zone()函數(shù)就是接收頁(yè)描述符的地址作為參數(shù),返回頁(yè)描述符中flag的高位,并到zone_table[ ]數(shù)組中確定相應(yīng)的管理區(qū)描述符的地址
slab算法是用來(lái)滿足對(duì)以頁(yè)框?yàn)閱挝坏恼?qǐng)求而設(shè)置的,簡(jiǎn)單介紹以下slab算法的原理
對(duì)于以頁(yè)為單位的請(qǐng)求發(fā)送到管理區(qū)分配器,然后管理區(qū)分配器搜索它所管轄的管理區(qū),找一個(gè)滿足請(qǐng)求的分配區(qū),然后再由這個(gè)管理區(qū)中的伙伴系統(tǒng)去處理,為了加快這個(gè)
過程,每個(gè)分區(qū)中還提供了一個(gè)每cpu頁(yè)框高速緩存,來(lái)處理單個(gè)頁(yè)框的請(qǐng)求。
這個(gè)過程中有四個(gè)請(qǐng)求頁(yè)框的函數(shù)和宏:
(1)alloc_pages, alloc_page返回分配的第一個(gè)頁(yè)框的頁(yè)描述符的地址
(2)__get_free_pages , __get_free_page 返回分配的第一個(gè)頁(yè)框的線性地址
其實(shí)二者是相同,因?yàn)橛袑iT用來(lái)處理線性地址到頁(yè)描述符地址轉(zhuǎn)換的函數(shù) virt_to_page() 實(shí)現(xiàn)從線性地址到頁(yè)描述符地址的轉(zhuǎn)換
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
