一般用戶空間關(guān)聯(lián)的物理頁(yè)面是按需通過(guò)缺頁(yè)異常的方式分配和調(diào)頁(yè),當(dāng)系統(tǒng)物理內(nèi)存不足時(shí)頁(yè)面回收算法會(huì)回收一些最近很少使用的頁(yè)面,但是有時(shí)候我們需要鎖住一些物理頁(yè)面防止其被回收(如時(shí)間有嚴(yán)格要求的應(yīng)用),Linux中提供了mlock相關(guān)的系統(tǒng)調(diào)用供用戶空間使用來(lái)鎖住部分或全部的地址空間關(guān)聯(lián)的物理頁(yè)面。 本文的分析基于arm64處理器架構(gòu),內(nèi)核版本為L(zhǎng)inux-5.10.27,我們會(huì)結(jié)合重點(diǎn)內(nèi)核源代碼來(lái)解析mlock是如何做到鎖住進(jìn)程地址空間關(guān)聯(lián)的物理內(nèi)存的,又是如何防止相關(guān)的物理頁(yè)面被交換出去的。
一、主動(dòng)缺頁(yè)
mlock的主要代碼處理流程如下,這里我們主要關(guān)注主動(dòng)缺頁(yè)部分:
mlock處理路徑中,會(huì)將VM_LOCKED標(biāo)志加入到vma->vm_flags中(由于設(shè)置的地址區(qū)域有可能跨越多個(gè)vma,所以代碼中會(huì)涉及到分裂和合并的操作,實(shí)質(zhì)上都會(huì)設(shè)置相關(guān)的vma->vm_flags的VM_LOCKED標(biāo)志),然后會(huì)調(diào)用__mm_populate來(lái)填充虛擬頁(yè)對(duì)應(yīng)的物理頁(yè),最終在faultin_page函數(shù)中試圖查找vma中的每個(gè)虛擬頁(yè)對(duì)應(yīng)的物理頁(yè)面(對(duì)應(yīng)于follow_page_mask函數(shù)),如果沒(méi)有找到會(huì)調(diào)用handle_mm_fault主動(dòng)觸發(fā)缺頁(yè)處理。 handle_mm_fault函數(shù)是內(nèi)核通用的缺頁(yè)異常處理例程,如vma是匿名映射的則分配物理頁(yè)面然后建立頁(yè)表映射關(guān)系,vma是文件映射則會(huì)從磁盤讀取對(duì)應(yīng)的文件頁(yè)(如果page cache沒(méi)有對(duì)應(yīng)頁(yè)面時(shí))到內(nèi)存的page cache,然后建立虛擬頁(yè)面建立頁(yè)表映射關(guān)系。
二、內(nèi)存回收處理
1. 掃描活躍的lru鏈表
內(nèi)存回收掃描活躍的lru鏈表時(shí),對(duì)于設(shè)定了VM_LOCKED的vma處理鏈路如下:
可以看到:當(dāng)掃描活躍的lru鏈表的時(shí)候,會(huì)通過(guò)反向映射機(jī)制查找到映射這個(gè)物理頁(yè)面的每個(gè)vma, 對(duì)于設(shè)置了vma->vm_flags 的VM_LOCKED標(biāo)志的vma來(lái)說(shuō)直接退出反向映射處理即可,不需要進(jìn)行訪問(wèn)計(jì)數(shù)的統(tǒng)計(jì)工作,本身這樣的物理頁(yè)面就需要常駐內(nèi)存不要進(jìn)行回收。
2.掃描不活躍的lru鏈表
內(nèi)存回收掃描不活躍的lru鏈表時(shí),對(duì)于設(shè)定了VM_LOCKED的vma處理鏈路如下:
可以看到:調(diào)用鏈中也會(huì)調(diào)用page_referenced 函數(shù)通過(guò)反向映射機(jī)制查找到映射這個(gè)物理頁(yè)面的每個(gè)vma, 對(duì)于設(shè)置了vma->vm_flags 的VM_LOCKED標(biāo)志的vma來(lái)說(shuō)直接退出反向映射處理即可,返回到page_check_references函數(shù)時(shí),判斷如果有vma設(shè)置了VM_LOCKED標(biāo)志就會(huì)返回PAGEREF_RECLAIM到shrink_page_list函數(shù)接著處理。 shrink_page_list函數(shù)在處理完page_check_references之后,就進(jìn)行回收處理,對(duì)于頁(yè)表映射頁(yè)會(huì)調(diào)用try_to_unmap來(lái)解除頁(yè)表映射。
3.反向映射處理
shrink_page_list在回收物理頁(yè)面之前會(huì)調(diào)用try_to_unmap來(lái)解除映射到這個(gè)頁(yè)面所有頁(yè)表項(xiàng),相關(guān)處理如下:
對(duì)于映射到這個(gè)物理頁(yè)的每個(gè)vma來(lái)說(shuō),如果vma->vm_flags設(shè)置了VM_LOCKED標(biāo)志,則會(huì)調(diào)用mlock_vma_page來(lái)做mlock處理,然后返回false,結(jié)束反向映射處理。 下面我們來(lái)看mlock_vma_page做了什么事情:
可以看到:mlock_vma_page首先設(shè)置頁(yè)描述符的PG_mlocked標(biāo)志,然后會(huì)zone的NR_MLOCK頁(yè)面記賬,然后會(huì)將頁(yè)面從原來(lái)的lru鏈表中隔離出來(lái),最后會(huì)將頁(yè)面加入不可回收的lru中(這個(gè)代碼大家自行閱讀,實(shí)際上是判斷頁(yè)描述符的PG_mlocked標(biāo)志)。
mlock_vma_page處理的重點(diǎn)就是將頁(yè)面加入到不可回收的lru鏈表,這樣內(nèi)存回收的時(shí)候就不會(huì)在掃描到這樣的頁(yè)面了。
mlock的整個(gè)過(guò)程如下圖所示:
三、munlock處理
munlock會(huì)解除原來(lái)鎖住的頁(yè)面,處理路徑如下:
當(dāng)然代碼中也會(huì)有對(duì)應(yīng)的vma的分裂處理,主要處理為:清除vma的VM_LOCKED標(biāo)志,清除頁(yè)描述符的PG_mlocked標(biāo)志,最后就會(huì)將原來(lái)在不可回收的lru中的頁(yè)面重新加入對(duì)應(yīng)的lru鏈表中。 這里還有一個(gè)細(xì)節(jié),那就是有可能這個(gè)頁(yè)面對(duì)多個(gè)vma共享,所以會(huì)通過(guò)try_to_munlock來(lái)處理,處理路徑如下:
會(huì)通過(guò)反向映射機(jī)制,遍歷這樣頁(yè)對(duì)應(yīng)的所有vma,如果傳遞的ttu_flags為TTU_MUNLOCK且vma->vm_flags沒(méi)有設(shè)置VM_LOCKED標(biāo)志,則直接返回,檢查下一個(gè)vma;如果有一個(gè)vma設(shè)置了VM_LOCKED標(biāo)志,說(shuō)明這個(gè)頁(yè)面還不能被回收,就會(huì)通過(guò)mlock_vma_page函數(shù)重新將頁(yè)面加入到不可回收的lru鏈表。 munlock的整個(gè)處理過(guò)程如下圖:
四、總結(jié)
對(duì)于一些對(duì)時(shí)間有嚴(yán)格要求的應(yīng)用場(chǎng)景,訪問(wèn)時(shí)按需分配和調(diào)頁(yè)機(jī)制的時(shí)延可能是未知的,內(nèi)核中提供了mlock相關(guān)的系統(tǒng)調(diào)用,用于將虛擬內(nèi)存區(qū)域?qū)?yīng)的物理頁(yè)面“鎖在”內(nèi)存中。內(nèi)核對(duì)應(yīng)mlock鎖住的頁(yè)面實(shí)際上它主要做了兩步比較重要的操作:1,調(diào)用mlock的時(shí)候就將所需要的物理頁(yè)面準(zhǔn)備好;2,內(nèi)存回收時(shí)當(dāng)掃描到相關(guān)的物理頁(yè)面時(shí),將其放入不可回收的lru鏈表。第一步保證訪問(wèn)的虛擬地址對(duì)應(yīng)的物理頁(yè)面在內(nèi)存中,第二步保證了鎖住的頁(yè)面不會(huì)被回收。
-
ARM
+關(guān)注
關(guān)注
134文章
9027瀏覽量
366490 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
2975瀏覽量
73815
原文標(biāo)題:mlock鎖原理剖析
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論