函數分析-----page_check_references shrink_active_list mark_page_accessed
首先看看頁面掃描回收大概過程, 然後分析三個函數如何進行頁面狀态變換
1.首先掃描非活躍連結清單中,然後當空閑頁面不夠時,掃描活動連結清單,并将相應頁面狀态變換。
2.然後回收非活躍連結清單,沒有設定頁描述符的字段 flags位PG_referenced頁。
一.mark_page_accessed函數
mark_page_accessed函數設定頁框通路狀态,并進行頁面狀态裝換,。(PG_active,PG_referenced)
(0,1)--->(1,0)
(1,0)--->(1,1)
(0,0)--->(0,1)
頁面狀态裝換圖如下:
第一個if語句:
将頁面狀态由 inactive,referenced 轉換為 active,unreferenced 即:(0,1)--->(1,0)
将頁面放入活動連結清單,并清空頁描述符的字段 flags位PG_referenced值
第二個if語句:
将頁面狀态由 active,unreferenced 轉換為 active,referenced 即:(1,0)--->(1,1)
仍舊保持在活動連結清單,并設定頁描述符的字段 flags位PG_referenced值
将頁面狀态由 inactive,unreferenced 轉換為 inactive,referenced 即:(0,0)--->(0,1)
仍舊保持在非活動連結清單,并設定頁描述符的字段 flags位PG_referenced值
void mark_page_accessed(struct page *page)
{
if (!PageActive(page) && !PageUnevictable(page) &&
PageReferenced(page) && PageLRU(page)) {
activate_page(page);
ClearPageReferenced(page);
} else if (!PageReferenced(page)) {
SetPageReferenced(page);
}
}
由此可見:
(0,0)--->(1,0)需要經過如下過程:
(0,0)--->(0,1) 和 (0,1)--->(1,0) 也就說不活躍連結清單中,沒有引用的頁面,需要兩次通路,才能放入活動連結清單
二.shrink_active_list函數
shrink_active_list函數将活動連結清單裝換為活動連結清單。頁面狀态裝換圖如下:
(1,0)---->(0,0)
(1,1)---->(0,1)
第一個if語句将(1,1)轉換為(0,1),但是有條件的。
其他情況直接轉換。
static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
struct scan_control *sc, int priority, int file)
{
if (page_referenced(page, 0, sc->mem_cgroup, &vm_flags)) {
nr_rotated += hpage_nr_pages(page);
if ((vm_flags & VM_EXEC) && page_is_file_cache(page)) {
list_add(&page->lru, &l_active);
continue;
}
}
ClearPageActive(page);
list_add(&page->lru, &l_inactive);
}
三.page_check_references
page_check_references函數傳回頁框狀态,并進行頁框狀态轉換(匿名頁特殊處理)。
如果此時頁框,沒有使用者通路頁框(可進行回收):
(0,1)->(0,0)
(0,0)->
如果此時頁框,由使用者通路頁框
(0,1)->(1,0)
(0,0)->(0,1)
前提:
頁框頁在非活躍連結清單
概念:
頁表項:
頁表儲存頁表項,頁表項儲存指向頁框的實體位址和頁框狀态位。其中第6為A(Accessed)位。當讀寫頁框時,作業系統這一位設定1, 當程序退出了,相應頁表項回收,并清空。
頁框描述符:
頁框描述符有一個字段 _mapcount,儲存指向頁框的頁表項數目。計數從-1開始,這個值意味着沒有頁表項指向頁框。如果計數為0,頁框不是共享的,如果大于1,頁框是共享的。
頁框描述符字段 flags位PG_referenced PG_reclaim 用于頁面回收對于 anonymous and file-backed pagecache
page_mapcount( )函數
參數頁框的描述符,傳回結果為_mapcount+1(例如1,為非共享)
page_mapped()函數
如果指向頁框的頁表項數目大于0,傳回真
page_check_references函數代碼過程:
1.擷取指向頁框的頁表項中,A(Accessed)位值, 置1意味着否有程序通路了該頁。
2.擷取頁描述符的字段 flags位PG_referenced值
3.如果A(Accessed)位值, 置1意味着否有程序通路了該頁, 如果該頁是匿名頁,該頁傳回活動連結清單, 否則設定頁框描述符字段 flags位PG_referenced,如果上次頁描述符的字段 flags位PG_referenced值為1,把該頁放入活動連結清單。否則仍舊儲存在非活動連結清單。
4.如果A(Accessed)位值為0, 上次頁描述符的字段 flags位PG_referenced值為1,頁是幹淨的(clean),可進行回收
5.如果A(Accessed)位值為0, 上次頁描述符的字段 flags位PG_referenced值為0, 可進行回收
由此可見:
對于不活躍連結清單中匿名頁,隻需要一次通路,可放入活動連結清單
不活躍連結清單中匿名頁,需要兩次通路,才能放入活動連結清單
static enum page_references page_check_references(struct page *page,
struct scan_control *sc)
{
int referenced_ptes, referenced_page;
unsigned long vm_flags;
referenced_ptes = page_referenced(page, 1, sc->mem_cgroup, &vm_flags);
referenced_page = TestClearPageReferenced(page);
if (vm_flags & VM_LOCKED)
return PAGEREF_RECLAIM;
if (referenced_ptes) {
if (PageAnon(page))
return PAGEREF_ACTIVATE;
SetPageReferenced(page);
if (referenced_page)
return PAGEREF_ACTIVATE;
return PAGEREF_KEEP;
}
if (referenced_page)
return PAGEREF_RECLAIM_CLEAN;
return PAGEREF_RECLAIM;
}