1. 程式人生 > >復合頁( Compound Page )

復合頁( Compound Page )

art 2個 單個 識別 post uget ges 方式 ren

復合頁(Compound Page)就是將物理上連續的兩個或多個頁看成一個
獨立的大頁,它能夠用來創建hugetlbfs中使用的大頁(hugepage)。
也能夠用來創建透明大頁(transparent huge page)子系統。可是
它不能用在頁緩存(page cache)中,這是由於頁緩存中管理的都是
單個頁。


分配一個復合頁的方式是:使用alloc_pages函數,參數order至少為1,
且設置__GFP_COMP標記。由於依據復合頁的定義,它通常包含2個或多
個連續的物理內存頁,這是由它的實現決定的,因而order參數不可能
為0。


通常調用alloc_pages的內存分配方式例如以下:


     p = alloc_pages(GFP_KERNEL, 2);


可是這樣的方式和創建一個復合頁有什麽不同呢?不同點就是在創建復合
頁的時候會創建與這個復合頁相關的元數據(metadata)。




表示復合頁的元數據都存在於Page結構體中,Page頁中的flag標記用來
識別復合頁。

在復合頁中,打頭的第一個普通頁成為“head page”,用
PG_head標記,而後面的全部頁被稱為“tail pages”,用PG_tail標記。
在64位系統中,能夠有多余的標記來表示復合頁的頁頭和頁尾;可是在
32位系統中卻沒有那麽多的標記,因此採用了一種復用其它標記的方案,
即將復合頁中的全部頁都用PG_compound標記,然後,對於尾頁同一時候也
使用PG_reclaim標記。這是由於PG_reclaim僅僅有在頁緩存中會用到,而

復合頁根本就不會在頁緩存中使用。


能夠使用PageCompound函數來檢測一個頁是否是復合頁,另外函數PageHead
和函數PageTail用來檢測一個頁是否是頁頭或者頁尾。

在每一個尾頁的page
結構體中都包括一個指向頭頁的指針 - first_page,能夠使用compound_head
函數獲得。


那麽當一個復合頁不再被系統使用時,我們怎樣知道該復合頁包括多少
個普通頁。又怎樣知道該復合頁的析構函數(destructor)存在哪裏呢?
首先,人們可能會覺得這些信息存在於頭頁的page結構體中,可是非常不
幸,在這個結構體中已經沒有可用的空間了。

因此,這些信息所有存儲
在第一個尾頁的lru字段中,將該復合頁的大小(order)首先強制轉換
為指針類型,然後存儲在lru.prev中,將析構函數存儲在lru.next中。


這裏就解釋了為什麽復合頁必須至少是兩個頁。


在內核中生命了兩個復合頁的析構函數。默認情況下會調用free_compound_page
來將全部的頁返回給系統的頁框分配器。而hugetlbfs子系統會調用free_huge_page
來做一些統計並釋放。


使用復合頁的最經典的一個樣例就是THP(transparent huge page)。
另外一些驅動使用復合頁來方便緩存的管理。


ref
===
1. https://lwn.net/Articles/619514/

復合頁( Compound Page )