Linux 內存管理的水位控制
分區頁框分配器之水位
在講分區頁框分配器分配內存的時候,進入夥伴算法前用函數 zone_watermark_fast(),來根據水位來判斷當前內存情況。內存夠的話採用夥伴算法分配,不夠的話通過 node_reclaim 回收內存。
水位的初始化
先看下水位的初始化:
int __meminit init_per_zone_wmark_min(void)
{
unsigned long lowmem_kbytes;
int new_min_free_kbytes;
lowmem_kbytes = nr_free_buffer_pages() * (PAGE_SIZE >> 10); ------ (1)
new_min_free_kbytes = int_sqrt(lowmem_kbytes * 16);
if (new_min_free_kbytes > user_min_free_kbytes) {
min_free_kbytes = new_min_free_kbytes; ------ (2)
if (min_free_kbytes < 128)
min_free_kbytes = 128;
if (min_free_kbytes > 65536)
min_free_kbytes = 65536;
} else {
pr_warn("min_free_kbytes is not updated to %d because user defined value %d is preferred\n",
new_min_free_kbytes, user_min_free_kbytes);
}
setup_per_zone_wmarks(); ------ (3)
refresh_zone_stat_thresholds();
setup_per_zone_lowmem_reserve(); ------ (4)
#ifdef CONFIG_NUMA
setup_min_unmapped_ratio();
setup_min_slab_ratio();
#endif
return 0;
}
core_initcall(init_per_zone_wmark_min)
(1). nr_free_buffer_pages 是獲取 ZONE_DMA 和 ZONE_NORMAL 區中高於 high 水位的總頁數 nr_free_buffer_pages = managed_pages - high_pages
(2). min_free_kbytes 是總的 min 大小,min_free_kbytes = 4 * sqrt(lowmem_kbytes)
(3). setup_per_zone_wmarks 根據總的 min 值,再加上各個 zone 在總內存中的佔比,然後通過 do_div 就計算出他們各自的 min 值,進而計算出各個 zone 的水位大小。min,low,high 的關係:low = min *125%,high = min * 150%。min,low,high 之間的比例關係與 watermark_scale_factor 相關。可以通過 /proc/sys/vm/watermark_scale_factor 設置
(4). setup_per_zone_lowmem_reserve 設置每個 zone 的 lowmem_reserve 大小。lowmem_reserve 值可以通過 /proc/sys/vm/lowmem_reserve_ratio 來修改。
爲什麼需要設置每個 zone 的保留內存呢,lowmem_reserve 的作用是什麼?
我們知道內核在分配內存時,會按照 HIGHMEM->NORMAL->DMA 的方向進行遍歷,如果當前 Zone 分配失敗,就會嘗試下一個低級的 Zone。我們可以想像應用進程通過內存映射申請 HIGHMEM,如果此時 HIGHMEM Zone 無法滿足分配,則會嘗試從 NORMAL 進行分配。這就有一個問題,來自 HIGHMEM Zone 的請求可能會耗盡 NORMAL Zone 的內存,最終的結果就是 NORMAL Zone 無內存提供給內核的正常分配。
因此針對這個場景,可以通過保留內存 lowmem_reserve[NORMAL] 給 NORMAL Zone 自己使用。
同樣當從 NORMAL Zone 失敗後,會嘗試從 zonelist 中的 DMA Zone 申請,通過 lowmem_reserve[DMA],限制來自 HIGHMEM 和 NORMAL 的分配請求。
$ cat /proc/sys/vm/lowmem_reserve_ratio
256 32
$ cat /proc/zoneinfo
Node 0, zone DMA32
......
pages free 361678
min 674
low 2874
high 3314
spanned 523776
present 496128
managed 440432
protection: (0, 3998, 3998)
......
Node 0, zone Normal
pages free 706981
min 1568
low 6681
high 7704
spanned 8912896
present 1048576
managed 1023570
protection: (0, 0, 0)
......
Node 0, zone Movable
pages free 0
min 0
low 0
high 0
spanned 0
present 0
managed 0
protection: (0, 0, 0)
-
spanned:表示當前 zone 所包含的所有的 pages
-
present:表示當前 zone 在去掉第一階段 kernel reserve 的內存之後剩下的 pages
-
managed:表示當前 zone 去掉初始化完成以後所有的 kernel reserve 的內存剩下的 pages
結合上面 arm64 平臺的數值舉個例子,假設這 2 個 Zones 分別包含 440432, 1023570 個 pages(實際是 / proc/zoneinfo 裏字段 managed 的值)。如下圖所示,使用每個區域的 managed pages 和 lowmem_reserve_ratio 計算每個區域的 lowmem_reserve 值,可以看出結果和 protection 值一樣。
水位的判斷
從這張圖可以看出:
-
如果空閒頁數目 min 值,則該 zone 非常缺頁,頁面回收壓力很大,應用程序寫內存操作就會被阻塞,直接在應用程序的進程上下文中進行回收,即 direct reclaim。
-
如果空閒頁數目小於 low 值,kswapd 線程將被喚醒。默認情況下,low 值爲 min 值的 125%,可以通過修改 watermark_scale_factor 來改變比例值
-
如果空閒頁面的值大於 high 值,kswapd 線程將睡眠。默認情況下,high 值爲 min 值的 150%,可以通過修改 watermark_scale_factor 來改變比例值
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Cb7am00qbCcPAZgtflmXyg