1. 程式人生 > >【儲存管理】頁面的定期換出do_try_to_free_pages()

【儲存管理】頁面的定期換出do_try_to_free_pages()

如果進過page_launder()後,如果可分配的物理頁面數量仍然不足,那就要進一步設法回收頁面,不過不是單純的從各個程序的使用者空間對映的頁面中回收,而是其它方面回收,一個是檔案關閉後並沒立即釋放的inode,dentry,作為LRU的後備,以防以後又要用到,用shrink_dcache_memory()和shrink_icache_memory()適當回收;一個是經由slab機制管理的動態分配的資料結構,它傾向於分配和保持過多的空閒物理頁面,而不是熱衷於換出,因此需要用kmem_cache_reap()來回收。

(1)在do_try_to_free_pages()中的refill_inactive()中,首先是通過kmem_cache_reap()回收由slab機制管理的空閒物理頁面,相對而言該動作是很小的;然後從低優先順序的開始來回收,判斷task_struct中的need_resched是1的話,說明某一箇中斷服務程式需要排程,要求schedule()讓核心再進行一次排程,但要把此程序設定成TASK_RUNNING,主要是因為核心執行緒永遠不會返回使用者空間(每當CPU結束一次系統呼叫和中斷服務或從系統空間返回到使用者空間時都會檢查該標誌),為了防止,佔住CPU不放,自己排程離開;

(2)在迴圈中,用refill_inactive_scan()掃描活躍頁面佇列,試圖找到可以轉入到不活躍狀態的頁面;用swap_out()找出一個程序,然後掃描其對映表,從中可以找到不活躍狀態的頁面,此外,還要嘗試dentry和inode結構的頁面;在refill_inactive_scan()中,根據優先順序來掃描活躍頁面佇列(優先順序為0時是整個活躍頁面佇列),來設定和移動相應的page結構; 

(3)swap_out()實際只是為把一些頁面交換到交換裝置上做準備,並不是物理意義上的換出;其中每一個程序中虛存頁面對應在記憶體的集合,稱為RSS;從init_task程序開始掃描一圈,找到最大的mm->swap_cnt反映的是該程序在一輪換出頁面的努力中尚未受到考察的頁面數量;如果一輪下來,沒有找到這樣的一個best物件,則設定assign再掃描一遍,跳到指定的標號select;而因最近因因異常換入(恢復對映)的頁面,將會等到下一次掃描;

(4)swap_out_mm()執行具體的換出,mm->swap_address為考察的頁面地址,首先根據該地址找到虛存區域vma,然後呼叫swap_out_vma()來試圖換出一個頁面,包括執行,其中執行包括以下幾個部分,swap_out_pgd(),swap_out_pmd(),try_to_swap_out();

(5)在try_to_swap_out()中,首先通過pte_present()來測試所指的物理頁面是否在記憶體中,不在即失敗,直接跳到標號out_failed;try_to_swap_out()返回失敗時,上一層的程式就會跳過這個頁面,而試著換出同一個頁面表對映的下一個頁面,如果該頁面表已經窮盡,就試著再往上層試下一個頁面表;物理頁面是在記憶體中時,通過pte_page將頁面表項的內容換算成指向物理頁面的page指標;判斷跳過一些在外部裝置上的物理頁面和不允許換出的保留頁面;接著具體考察一個頁面,一個物理頁面是否應該換出,取決於這個歌頁面是否受到了訪問,通過pte_test_and_clear_young()來測試_PAGE_BIT_ACCESSED位,如果是1的話說明上一次對同一個頁面表項仍在使用,說明頁面還很年輕,不易換出,此函式清_PAGE_BIT_ACCESSED位,把它會寫到頁面表項,為下一次再測試這個標誌做準備,還要使用SetPageRerenced將page資料結構中的PG_reference標誌置1,即將頁面表項中受到過訪問的資訊轉移至頁面的資料結構中,並通過age_page_up()來增加頁面可以留下來觀察的時間;

(6)如果頁面不再年輕,linux核心還是給他機會的,檢視多久也就要看page->age,當它為0時,我們就可以換出物件了,首先檢視該物理頁面是否被鎖住,鎖住的話,直接返回到標號out_failed,加鎖成功後,根據頁面不同情況做換出的準備了;若page已在swapper_space頁面換入換出佇列(髒和乾淨兩個)中,說明頁面已在交換裝置中;使用swap_duplicate()來對swap_entry_t做一些檢驗和遞增相應盤上頁面的共享計數;使用set_pte()把那個盤上頁面的索引項置入相應的頁面表項,原先對記憶體頁面的對映變成了對盤上頁面的對映,這樣RSS頁面也就少了一個頁面;使用deactivate()有條件的將page設定成不活躍狀態,要考慮三種情況(分配時,使用者空間對映,記憶體模擬磁碟),將頁面轉入相應的不活躍髒/乾淨佇列;

(7)對於頁面page不在swapper_space頁面換入換出佇列(髒和乾淨兩個)中時,說明尚未為頁面在交換裝置上建立起映像,或頁面來自的是一個檔案(若提供vm_operations中的nopage操作,說明頁面來自檔案不是交換裝置,此時可根據虛存地址計算出檔案中的頁面位置,否則就是普通頁面,但尚未建立盤上頁面);最後頁面如果很久沒有訪問到,在swapper_space佇列時,也不是檔案對映,也是個髒頁面,就為它分配一個盤上頁面,然後將該盤上頁面放入到swapper_space佇列中以及活躍的頁面佇列中,再通過set_page_dirty將頁面轉到不活躍髒佇列中,再使用

page_launder()來洗淨;

(8)kreclaimd與kswapd類似,task_struct中的flags欄位PF_MEMALLOC都被設定成1,表示它們都是頁面管理機制的維護者,kreclaimd中通過reclaim_page()掃描各個頁面管理區的不活躍乾淨頁面佇列,從中回收頁面加以釋放。