專題:Linux內存管理專題
關鍵詞:匿名頁面、換入、換出。
如果要將匿名頁面的生命周期進行划分,大概就是誕生、使用、換出、換入和銷毀。
內核中使用匿名頁面的地方有很多,產生缺頁中斷之后匿名頁面就誕生了;
用戶進程訪問虛擬地址即可訪問到匿名頁面內容;
在內存緊張的時候,需要回收一些頁面來釋放內存,匿名頁面可能被換出;
如果虛擬地址空間被再次訪問,則需要將swap分區中內容換入;
當進程關閉或者退出時,VMA上的映射需要被清除,相關匿名頁面會被銷毀。
1. 匿名頁面的誕生
從內核的角度看,出現匿名頁面的情況有:
1. 用戶空間malloc/mmap接口函數來分配內存,在內核空間發生缺頁中斷時,調用do_anonymous_page()會產生匿名頁面。
2. 發生寫時復制,當缺頁中斷出現寫保護錯誤時,新分配的頁面是匿名頁面。
2.1 do_wp_page(),只讀的special映射的頁面,例如映射到zeroed的頁面;非單身匿名頁面;只讀的私有映射的page cache;KSM頁面。
2.2 do_cow_page(),共享的匿名頁面(shared anonymous mapping, shmm)
3. do_swap_page(),從swap分區 讀回數據時會新分配匿名頁面。
4. 遷移頁面
2. 匿名頁面的使用
匿名頁面在缺頁中斷中分配完成之后,就建立了進程虛擬地址空間VMA和物理頁面的映射關系,用戶進程訪問虛擬地址即訪問到匿名頁面的內容。
3. 匿名頁面的換出
假設系統內存緊張,需要回收一些頁面來釋放內存。
anon_page剛分配時會加入活躍LRU鏈表(LRU_ACTIVE_ANON)頭部,在經歷了活躍LRU鏈表的一段時間的移動,
該anon_page到達活躍LRU鏈表的尾部,shrink_active_list()函數把該頁加入不活躍LRU鏈表(LRU_INACTIVE_LRU)。
shrink_inactive_list()函數掃描不活躍鏈表,shrink_page_list()回首頁面。
(1) 第一次掃描不活躍鏈表時,shrink_page_list()->add_to_swap()函數會為該頁分配swap分區空間
此時匿名頁面的_count、_mapcount、flags狀態如下:
page->_count = 3(引用計數增加的地方:1-分配頁面;2-分離頁面;3-add_to_swap())
page->_mapcount = 0
page->flags = PG_lru | PG_swapbacked PG_swapcache | PG_dirty | PG_uptedate | PG_locked,
PG_swapcache表示該頁已經分配了swap空間,PG_dirty表示該頁為臟,稍后需要寫回swap分區,PG_uptodate表示該也得數據是有效的。
(2) shrink_page_list()->try_to_unmap()后該匿名頁面狀態如下
page->_count = 2
page->_mapcount = -1---------表示沒有PTE映射該頁
try_to_unmap()會通過RMAP反響映射系統去尋找映射該頁的所有VMA和相應的PTE,並將這些PTE解除映射。
因為該頁只和父進程建立了映射關系,因此_count和_mapcount都要減1。
(3) shrink_page_list()->pageout()函數把該頁寫回交換分區,此時匿名頁面狀態如下
page->_count = 2
page->_mapcount = -1
page->flags = PG_lru | PG_swapbacked | PG_swapcache | PG_dirty | PG_uptedate | PG_reclaim | PG_writeback
(4) 第二次掃描不活躍鏈表
經歷第一次不活躍LRU鏈表的移動過程,從鏈表頭移動到鏈表尾。
如果這時該頁還沒有寫入完成,即PG_writeback標志位還在,那么該頁會繼續被放回到不活躍LRU鏈表頭,kswapd會繼續掃描其它頁,從而繼續等待寫完成。
假設第二次掃描不活躍鏈表時,該頁寫入swap分區已經完成。Block Layer層毀掉函數end_swap_bio_write()->end_page_writeback()完成如下動作:
- 清PG_writeback標志位
- 喚醒等待在該頁PG_writeback的線程,見wake_up_page(page, PG_writeback)函數。
shrink_page_list()->__remove_mapping()執行后如下:
page->_count = 0
page->_mapcount = -1
page->flags = PG_swapbacked | PG_uptedate
最后把page加入free_page鏈表中,釋放該頁。因此該anon_page頁的狀態是頁面內容已經寫入swap分區,實際物理頁面已經釋放。
4. 匿名頁面的換入
匿名頁面被換出到swap分區后,如果應用程序需要讀寫這個頁面,缺頁中斷發生。
因為pte中的L_PTE_PRESENT比特位顯示該物理頁面不在內存中,但PTE表項不為空,說明該頁被交換到swap分區去了,因此調用do_swap_page()函數重新讀入該頁的內容。
5. 匿名頁面銷毀
當用戶進程關閉或者退出時,會掃描這個用戶進程所有的VMAs,並會清除這些VMA上所有的映射,如果符合這些標准,相關頁面會被釋放。
