透明巨頁支援¶
目標¶
處理大型記憶體工作集的效能關鍵型計算應用程式已經在 libhugetlbfs 和 hugetlbfs 之上執行。 透明巨頁支援 (THP) 是一種使用巨頁支援虛擬記憶體的替代方法,它支援頁面大小的自動提升和降級,並且沒有 hugetlbfs 的缺點。
目前,THP 僅適用於匿名記憶體對映和 tmpfs/shmem。 但將來它可以擴充套件到其他檔案系統。
注意
在下面的示例中,我們假定基本頁面大小為 4K,巨頁大小為 2M,儘管實際數字可能因 CPU 架構而異。
應用程式執行速度更快的原因有兩個。 第一個因素幾乎完全無關緊要,而且沒有什麼意義,因為它也會帶來在缺頁中斷中需要更大的清除頁面複製頁面的缺點,這可能是一個負面影響。 第一個因素包括為使用者空間觸及的每個 2M 虛擬區域獲取單個缺頁中斷(因此將進入/退出核心的頻率降低了 512 倍)。 這僅在記憶體對映生命週期內第一次訪問記憶體時才重要。 第二個持久且更重要的因素將影響應用程式整個執行時對記憶體的所有後續訪問。 第二個因素包括兩個組成部分
TLB 未命中將執行得更快(尤其是在使用巢狀頁表的虛擬化中,但幾乎總是在沒有虛擬化的裸機上也是如此)
單個 TLB 條目將對映更大的虛擬記憶體量,從而減少 TLB 未命中的數量。 對於使用巢狀頁表的虛擬化,只有當 KVM 和 Linux 客戶機都使用巨頁時,TLB 才能對映更大的尺寸,但僅僅因為 TLB 未命中執行得更快,即使只有其中一個使用巨頁,也會發生顯著的加速。
現代核心支援“多大小 THP”(mTHP),它引入了以大於基本頁面但小於傳統 PMD 大小(如上所述)的塊分配記憶體的能力,增量為 2 的冪次方的頁面數。 mTHP 可以支援匿名記憶體(例如 16K、32K、64K 等)。 這些 THP 繼續以 PTE 對映,但在許多情況下仍然可以提供與上述類似的優勢:缺頁中斷顯著減少(例如,減少 4 倍、8 倍、16 倍等),但延遲峰值不太突出,因為每個頁面的大小不像 PMD 大小的變體那樣巨大,並且在每個缺頁中斷中需要清除的記憶體更少。 某些架構還採用 TLB 壓縮機制,以便在 PTE 集在虛擬和物理上連續且適當對齊時擠壓更多條目。 在這種情況下,TLB 未命中將不太頻繁地發生。
THP 可以系統範圍內啟用,也可以限制為某些任務,甚至限制在任務地址空間內的記憶體範圍。 除非 THP 完全停用,否則有一個 khugepaged 守護程序掃描記憶體並將基本頁面序列摺疊成 PMD 大小的巨頁。
THP 的行為透過 sysfs 介面以及使用 madvise(2) 和 prctl(2) 系統呼叫來控制。
與 hugetlbfs 的預留方法相比,透明巨頁支援透過允許所有未使用的記憶體用作快取或其他可移動(甚至不可移動的實體)來最大限度地提高空閒記憶體的利用率。 它不需要預留以防止使用者空間注意到巨頁分配失敗。 它允許在巨頁上使用分頁和所有其他高階 VM 功能。 它不需要應用程式進行修改即可利用它。
但是,應用程式可以進一步最佳化以利用此功能,就像之前已經最佳化過以避免為每個 malloc(4k) 產生大量的 mmap 系統呼叫一樣。 最佳化使用者空間遠非強制性的,即使對於處理大量記憶體的巨頁感知較差的應用程式,khugepaged 也可以處理長期存在的頁面分配。
在某些情況下,當系統範圍內啟用巨頁時,應用程式最終可能會分配更多的記憶體資源。 應用程式可能會 mmap 一個很大的區域,但只觸及其中的 1 個位元組,在這種情況下,可能會分配一個 2M 的頁面而不是一個 4k 的頁面,這樣做沒有好處。 這就是為什麼可以停用系統範圍內的巨頁,而只在 MADV_HUGEPAGE madvise 區域中使用它們的原因。
嵌入式系統應僅在 madvise 區域內啟用巨頁,以消除浪費任何寶貴位元組記憶體的風險,並僅執行得更快。
從巨頁中獲得很多好處並且不會因使用巨頁而有丟失記憶體風險的應用程式,應在其關鍵的 mmapped 區域上使用 madvise(MADV_HUGEPAGE)。
sysfs¶
全域性 THP 控制¶
可以完全停用用於匿名記憶體的透明巨頁支援(主要用於除錯目的),或者僅在 MADV_HUGEPAGE 區域內啟用(以避免消耗更多記憶體資源的風險),或者在系統範圍內啟用。 可以透過以下方式針對每個支援的 THP 大小實現此目的
echo always >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
echo never >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
其中 <size> 是正在定址的巨頁大小,可用大小因系統而異。
例如
echo always >/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled
或者,可以指定給定的巨頁大小將繼承頂層“enabled”值
echo inherit >/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled
例如
echo inherit >/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled
可以使用以下命令之一設定頂層設定(用於“inherit”)
echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled
預設情況下,PMD 大小的巨頁具有 enabled="inherit",所有其他巨頁大小具有 enabled="never"。 如果啟用多個巨頁大小,核心將為給定的分配選擇最合適的已啟用大小。
還可以限制 VM 中的碎片整理工作,以生成匿名巨頁,以防它們不能立即用於 madvise 區域,或者永遠不要嘗試對記憶體進行碎片整理,除非巨頁立即可用,否則只需回退到常規頁面。 顯然,如果我們花費 CPU 時間來整理記憶體,我們希望透過以後使用巨頁而不是常規頁面來獲得更多收益。 這並不能總是保證,但如果分配用於 MADV_HUGEPAGE 區域,則可能更有可能。
echo always >/sys/kernel/mm/transparent_hugepage/defrag
echo defer >/sys/kernel/mm/transparent_hugepage/defrag
echo defer+madvise >/sys/kernel/mm/transparent_hugepage/defrag
echo madvise >/sys/kernel/mm/transparent_hugepage/defrag
echo never >/sys/kernel/mm/transparent_hugepage/defrag
- always
表示請求 THP 的應用程式將在分配失敗時停止,並直接回收頁面和壓縮記憶體,以立即分配 THP。 這對於從 THP 使用中受益匪淺並願意延遲 VM 啟動以利用它們的虛擬機器來說是可取的。
- defer
表示應用程式將在後臺喚醒 kswapd 以回收頁面,並喚醒 kcompactd 以壓縮記憶體,以便在不久的將來可以使用 THP。 然後由 khugepaged 負責稍後安裝 THP 頁面。
- defer+madvise
將像
always一樣進入直接回收和壓縮,但僅適用於已使用 madvise(MADV_HUGEPAGE) 的區域; 所有其他區域將在後臺喚醒 kswapd 以回收頁面,並喚醒 kcompactd 以壓縮記憶體,以便在不久的將來可以使用 THP。- madvise
將像
always一樣進入直接回收,但僅適用於已使用 madvise(MADV_HUGEPAGE) 的區域。 這是預設行為。- never
應該是不言自明的。
預設情況下,核心嘗試在讀取缺頁中斷時使用巨大的、PMD 可對映的零頁面來匿名對映。 可以透過寫入 0 來停用巨大的零頁面,或者透過寫入 1 來重新啟用它
echo 0 >/sys/kernel/mm/transparent_hugepage/use_zero_page
echo 1 >/sys/kernel/mm/transparent_hugepage/use_zero_page
某些使用者空間(例如測試程式或最佳化的記憶體分配庫)可能想知道 PMD 可對映透明巨頁的大小(以位元組為單位)
cat /sys/kernel/mm/transparent_hugepage/hpage_pmd_size
所有在缺頁中斷和摺疊時的 THP 都將被新增到 _deferred_list 中,因此如果它們被認為是“未充分利用”,將在記憶體壓力下被拆分。 如果 THP 中填充零的頁面的數量高於 max_ptes_none(參見下文),則 THP 未被充分利用。 可以透過寫入 0 到 shrink_underused 來停用此行為,並透過寫入 1 到它來啟用它
echo 0 > /sys/kernel/mm/transparent_hugepage/shrink_underused
echo 1 > /sys/kernel/mm/transparent_hugepage/shrink_underused
當啟用 PMD 大小的 THP 時(per-size anon 控制或頂層控制設定為“always”或“madvise”),khugepaged 將自動啟動,當停用 PMD 大小的 THP 時(per-size anon 控制和頂層控制都為“never”),它將自動關閉
Khugepaged 控制¶
注意
khugepaged 目前僅搜尋摺疊到 PMD 大小的 THP 的機會,並且沒有嘗試摺疊到其他 THP 大小。
khugepaged 通常以低頻率執行,因此雖然可能不想在缺頁中斷期間同步呼叫碎片整理演算法,但至少在 khugepaged 中呼叫碎片整理應該是值得的。 但是,也可以透過寫入 0 來停用 khugepaged 中的碎片整理,或者透過寫入 1 來啟用 khugepaged 中的碎片整理
echo 0 >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
echo 1 >/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
您還可以控制 khugepaged 每次掃描多少頁
/sys/kernel/mm/transparent_hugepage/khugepaged/pages_to_scan
以及 khugepaged 在每次傳遞之間等待多少毫秒(您可以將其設定為 0 以 100% 利用一個核心執行 khugepaged)
/sys/kernel/mm/transparent_hugepage/khugepaged/scan_sleep_millisecs
以及如果在巨頁分配失敗時 khugepaged 等待多少毫秒來限制下一次分配嘗試
/sys/kernel/mm/transparent_hugepage/khugepaged/alloc_sleep_millisecs
可以在摺疊的頁面數量中看到 khugepaged 的進度(請注意,此計數器可能不是摺疊的頁面數量的精確計數,因為“摺疊”可能意味著多種含義:(1)PTE 對映被 PMD 對映替換,或(2)所有 4K 物理頁面被一個 2M 巨頁替換。 每個可能獨立發生,或一起發生,具體取決於記憶體型別和發生的故障。 因此,此值應大致解釋為進度的標誌,並且應諮詢 /proc/vmstat 中的計數器以進行更準確的核算)
/sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed
對於每次傳遞
/sys/kernel/mm/transparent_hugepage/khugepaged/full_scans
max_ptes_none 指定在將一組小頁面摺疊成一個大頁面時可以分配多少個額外的小頁面(尚未對映)
/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none
較高的值會導致程式使用更多的記憶體。 較低的值會導致更少的 thp 效能。 max_ptes_none 的值可以浪費非常少的 cpu 時間,您可以忽略它。
max_ptes_swap 指定在將一組頁面摺疊成透明巨頁時可以從交換空間中調入多少個頁面
/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_swap
較高的值可能導致過多的交換 IO 並浪費記憶體。 較低的值可以阻止 THP 被摺疊,導致更少的頁面被摺疊成 THP,並降低記憶體訪問效能。
max_ptes_shared 指定可以在多個程序之間共享多少個頁面。 如果 THP 的任何頁面被共享,khugepaged 可能會將 THP 的頁面視為共享。 超過此數量將阻止摺疊
/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_shared
較高的值可能會增加某些工作負載的記憶體佔用。
啟動引數¶
您可以透過將引數 transparent_hugepage=always 或 transparent_hugepage=madvise 或 transparent_hugepage=never 傳遞到核心命令列來更改頂層“enabled”控制的 sysfs 啟動時間預設值。
或者,可以透過傳遞 thp_anon=<size>[KMG],<size>[KMG]:<state>;<size>[KMG]-<size>[KMG]:<state> 來控制每個支援的匿名 THP 大小,其中 <size> 是 THP 大小(必須是 PAGE_SIZE 的 2 的冪次且受支援的匿名 THP),並且 <state> 是 always、madvise、never 或 inherit 之一。
例如,以下設定將 16K、32K、64K THP 設定為 always,將 128K、512K 設定為 inherit,將 256K 設定為 madvise,並將 1M、2M 設定為 never
thp_anon=16K-64K:always;128K,512K:inherit;256K:madvise;1M-2M:never
可以多次指定 thp_anon= 以根據需要配置所有 THP 大小。 如果至少指定一次 thp_anon=,則命令列上未顯式配置的任何匿名 THP 大小將隱式設定為 never。
transparent_hugepage 設定僅影響全域性切換。 如果未指定 thp_anon,則 PMD_ORDER THP 將預設為 inherit。 但是,如果使用者提供了有效的 thp_anon 設定,則 PMD_ORDER THP 策略將被覆蓋。 如果 PMD_ORDER 的策略未在有效的 thp_anon 中定義,則其策略將預設為 never。
與 transparent_hugepage 類似,您可以使用核心引數 transparent_hugepage_shmem=<policy> 來控制內部 shmem 掛載的巨頁分配策略,其中 <policy> 是 shmem 的七個有效策略之一(always、within_size、advise、never、deny 和 force)。
與 transparent_hugepage_shmem 類似,您可以使用核心引數 transparent_hugepage_tmpfs=<policy> 來控制 tmpfs 掛載的預設巨頁分配策略,其中 <policy> 是 tmpfs 的四個有效策略之一(always、within_size、advise、never)。 tmpfs 掛載的預設策略是 never。
與 thp_anon 控制每個支援的匿名 THP 大小的方式相同,thp_shmem 控制每個支援的 shmem THP 大小。 thp_shmem 的格式與 thp_anon 相同,但也支援策略 within_size。
可以多次指定 thp_shmem= 以根據需要配置所有 THP 大小。 如果至少指定一次 thp_shmem=,則命令列上未顯式配置的任何 shmem THP 大小將隱式設定為 never。
transparent_hugepage_shmem 設定僅影響全域性切換。 如果未指定 thp_shmem,則 PMD_ORDER 巨頁將預設為 inherit。 但是,如果使用者提供了有效的 thp_shmem 設定,則 PMD_ORDER 巨頁策略將被覆蓋。 如果 PMD_ORDER 的策略未在有效的 thp_shmem 中定義,則其策略將預設為 never。
tmpfs/shmem 中的巨頁¶
傳統上,tmpfs 僅支援單個巨頁大小 ("PMD")。 今天,它也像匿名記憶體一樣支援更小的大小,通常稱為“多大小 THP”(mTHP)。 任何大小的巨頁通常在核心中表示為“大 folio”。
雖然可以對用於內部 shmem 掛載的巨頁大小進行精細控制(請參見下文),但普通 tmpfs 掛載將利用所有可用的巨頁大小,而無需對確切大小進行任何控制,其行為更類似於其他檔案系統。
tmpfs 掛載¶
可以使用掛載選項調整 tmpfs 掛載的 THP 分配策略: huge=。 它可以具有以下值
- always
每次需要新頁面時都嘗試分配巨頁;
- never
不要分配巨頁;
- within_size
僅當它完全在 i_size 內時才分配巨頁。 還要尊重 madvise() 提示;
- advise
僅在透過 madvise() 請求時才分配巨頁;
請記住,核心可以使用所有可用大小的巨頁,並且無法像內部 tmpfs 掛載那樣進行精細控制。
過去的預設策略是 never,但現在可以使用核心引數 transparent_hugepage_tmpfs=<policy> 進行調整。
mount -o remount,huge= /mountpoint 在掛載後工作正常:重新掛載 huge=never 完全不會嘗試分解巨頁,只會阻止分配更多巨頁。
除了上面列出的策略之外,當設定為以下值時,sysfs knob /sys/kernel/mm/transparent_hugepage/shmem_enabled 將影響 tmpfs 掛載的分配策略
- deny
用於緊急情況,以強制從所有掛載中關閉 huge 選項;
- force
強制為所有掛載啟用 huge 選項 - 對於測試非常有用;
shmem / 內部 tmpfs¶
內部 tmpfs 掛載用於 SysV SHM、memfds、共享匿名 mmaps(/dev/zero 或 MAP_ANONYMOUS)、GPU 驅動程式的 DRM 物件、Ashmem。
要控制此內部 tmpfs 掛載的 THP 分配策略,可以使用 sysfs knob /sys/kernel/mm/transparent_hugepage/shmem_enabled 以及 '/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/shmem_enabled' 中每個 THP 大小的 knobs。
全域性 knob 具有與 tmpfs 掛載的 huge= 掛載選項相同的語義,不同之處在於可以單獨控制不同的巨頁大小,並且只有當每個大小的 knob 設定為“inherit”時才會使用全域性 knob 的設定。
對於各個大小,將刪除選項“force”和“deny”,這些選項是舊時代的測試產物。
- always
每次需要新頁面時都嘗試分配 <size> 巨頁;
- inherit
繼承頂層“shmem_enabled”值。 預設情況下,PMD 大小的巨頁具有 enabled="inherit",所有其他巨頁大小具有 enabled="never";
- never
不要分配 <size> 巨頁;
- within_size
僅當它完全在 i_size 內時才分配 <size> 巨頁。 還要尊重 madvise() 提示;
- advise
僅在透過 madvise() 請求時才分配 <size> 巨頁;
需要重新啟動應用程式¶
transparent_hugepage/enabled 和 transparent_hugepage/hugepages-<size>kB/enabled 值以及 tmpfs 掛載選項僅影響未來的行為。 因此,要使它們生效,您需要重新啟動任何可能一直在使用巨頁的應用程式。 這也適用於 khugepaged 中註冊的區域。
監控使用情況¶
系統當前使用的 PMD 大小的匿名透明巨頁的數量可以透過讀取 /proc/meminfo 中的 AnonHugePages 欄位獲得。 要確定哪些應用程式正在使用 PMD 大小的匿名透明巨頁,需要讀取 /proc/PID/smaps 並計算每個對映的 AnonHugePages 欄位。(請注意,由於歷史原因,AnonHugePages 僅適用於傳統的 PMD 大小的 THP,應該稱為 AnonHugePmdMapped)。
對映到使用者空間的檔案透明巨頁的數量可以透過讀取 /proc/meminfo 中的 ShmemPmdMapped 和 ShmemHugePages 欄位獲得。 要確定哪些應用程式正在對映檔案透明巨頁,需要讀取 /proc/PID/smaps 並計算每個對映的 FilePmdMapped 欄位。
請注意,讀取 smaps 檔案成本很高,並且頻繁讀取會產生開銷。
/proc/vmstat 中有許多計數器可用於監控系統成功提供巨頁以供使用的情況。
- thp_fault_alloc
每次成功分配巨頁並將其記入處理缺頁中斷時,該值都會遞增。
- thp_collapse_alloc
當 khugepaged 找到要摺疊成一個巨頁的頁面範圍併成功分配新的巨頁來儲存資料時,該值會遞增。
- thp_fault_fallback
如果缺頁中斷無法分配或記入巨頁,而是回退到使用小頁面,則該值會遞增。
- thp_fault_fallback_charge
如果缺頁中斷無法記入巨頁,而是回退到使用小頁面,即使分配成功,該值也會遞增。
- thp_collapse_alloc_failed
如果 khugepaged 找到應該摺疊成一個巨頁的頁面範圍但分配失敗,則該值會遞增。
- thp_file_alloc
每次成功分配 shmem 巨頁時,該值都會遞增(請注意,儘管以“file”命名,但計數器僅測量 shmem)。
- thp_file_fallback
如果嘗試分配 shmem 巨頁但失敗,而是回退到使用小頁面,則該值會遞增。(請注意,儘管以“file”命名,但計數器僅測量 shmem)。
- thp_file_fallback_charge
如果無法記入 shmem 巨頁,而是回退到使用小頁面,即使分配成功,該值也會遞增。(請注意,儘管以“file”命名,但計數器僅測量 shmem)。
- thp_file_mapped
每次將檔案或 shmem 巨頁對映到使用者地址空間時,該值都會遞增。
- thp_split_page
每次將巨頁拆分為基本頁面時,該值都會遞增。 這可能會因各種原因而發生,但一個常見原因是巨頁已過時並且正在被回收。 此操作意味著拆分所有 PMD 頁面對映的頁面。
- thp_split_page_failed
如果核心無法拆分巨頁,則該值會遞增。 如果頁面被某人鎖定,則可能會發生這種情況。
- thp_deferred_split_page
當將巨頁放入拆分佇列時,該值會遞增。 當巨頁被部分取消對映並且拆分它可以釋放一些記憶體時,會發生這種情況。 拆分佇列中的頁面將在記憶體壓力下拆分。
- thp_underused_split_page
當分割佇列上的大頁因利用率不足而被分割時,該計數器會遞增。如果 THP 中的零頁數量超過某個閾值(/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none),則認為 THP 利用率不足。
- thp_split_pmd
每次 PMD 分割成 PTE 表時,該計數器都會遞增。例如,當應用程式對大頁的一部分呼叫 mprotect() 或 munmap() 時,可能會發生這種情況。它不會分割大頁,只會分割頁表項。
- thp_zero_page_alloc
每次成功分配用於 thp 的巨大零頁時,該計數器都會遞增。請注意,它不會統計巨大零頁的每次對映,僅統計其分配。
- thp_zero_page_alloc_failed
如果核心未能分配巨大的零頁,並且回退到使用小頁面,則該計數器會遞增。
- thp_swpout
每次將大頁作為一個整體換出而沒有分割時,該計數器都會遞增。
- thp_swpout_fallback
如果大頁在換出之前必須分割,則該計數器會遞增。通常是因為未能為該大頁分配一些連續的交換空間。
在 /sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/stats 中,還有每個大頁大小的單獨計數器,可用於監視系統在提供大頁以供使用方面的效率。每個計數器都有其對應的檔案。
- anon_fault_alloc
每次成功分配巨頁並將其記入處理缺頁中斷時,該值都會遞增。
- anon_fault_fallback
如果頁面錯誤未能分配或收取大頁的費用,而是回退到使用較低階的大頁或小頁,則該計數器會遞增。
- anon_fault_fallback_charge
即使分配成功,如果頁面錯誤未能收取大頁的費用,而是回退到使用較低階的大頁或小頁,則該計數器會遞增。
- zswpout
每次將大頁作為一個整體換出到 zswap 而沒有分割時,該計數器都會遞增。
- swpin
每次將大頁從非 zswap 交換裝置作為一個整體換入時,該計數器都會遞增。
- swpin_fallback
如果 swapin 未能分配或收取大頁的費用,而是回退到使用較低階的大頁或小頁,則該計數器會遞增。
- swpin_fallback_charge
即使分配成功,如果 swapin 未能收取大頁的費用,而是回退到使用較低階的大頁或小頁,則該計數器會遞增。
- swpout
每次將大頁作為一個整體換出到非 zswap 交換裝置而沒有分割時,該計數器都會遞增。
- swpout_fallback
如果大頁在換出之前必須分割,則該計數器會遞增。通常是因為未能為該大頁分配一些連續的交換空間。
- shmem_alloc
每次成功分配 shmem 大頁時,該計數器都會遞增。
- shmem_fallback
如果嘗試分配 shmem 大頁但失敗,而是回退到使用小頁,則該計數器會遞增。
- shmem_fallback_charge
如果 shmem 大頁無法收取費用,而是回退到使用小頁(即使分配成功),則該計數器會遞增。
- split
每次成功將大頁分割成較小階數時,該計數器都會遞增。 發生這種情況的原因有很多,但一個常見的原因是大頁已舊,正在被回收。
- split_failed
如果核心無法拆分巨頁,則該值會遞增。 如果頁面被某人鎖定,則可能會發生這種情況。
- split_deferred
當大頁被放入分割佇列時,該計數器會遞增。 當大頁被部分取消對映並且分割它可以釋放一些記憶體時,會發生這種情況。 分割佇列上的頁面將在記憶體壓力下分割(如果可以分割)。
- nr_anon
系統中存在的匿名 THP 的數量。 這些 THP 可能當前已完全對映,或者具有部分取消對映/未使用的子頁面。
- nr_anon_partially_mapped
可能部分對映、可能浪費記憶體並且已排隊等待延遲記憶體回收的匿名 THP 的數量。 請注意,在某些極端情況下(例如,遷移失敗),我們可能會將匿名 THP 檢測為“部分對映”並在此處計數,即使它實際上不再是部分對映。
隨著系統老化,分配大頁可能會很昂貴,因為系統使用記憶體壓縮在記憶體中複製資料以釋放一個大頁以供使用。 /proc/vmstat 中有一些計數器可以幫助監視此開銷。
- compact_stall
每次程序停頓以執行記憶體壓縮,以便釋放一個大頁以供使用時,該計數器都會遞增。
- compact_success
如果系統壓縮了記憶體並釋放了一個大頁以供使用,則該計數器會遞增。
- compact_fail
如果系統嘗試壓縮記憶體但失敗,則該計數器會遞增。
可以使用函式跟蹤器記錄在 __alloc_pages() 中花費的時間,並使用 mm_page_alloc 跟蹤點識別哪些分配用於大頁,從而確定停頓的持續時間。
最佳化應用程式¶
為了保證核心會立即在任何記憶體區域中對映 THP,mmap 區域必須與 hugepage 自然對齊。 posix_memalign() 可以提供這種保證。
Hugetlbfs¶
您可以在啟用透明大頁支援的核心上像往常一樣使用 hugetlbfs。 hugetlbfs 中沒有其他區別,只是整體碎片會更少。 屬於 hugetlbfs 的所有常用功能都將保留且不受影響。 libhugetlbfs 也能像往常一樣正常工作。