内存管理参数min_free_kbytes 分析
Contents
在Linux
系统中,有很多内存管理的配置参数,本文就详细分析min_free_kbytes
参数。
系统环境介绍
- 发行版:
centos7.5
- 内核版本:3.10.0-862.14.4.el7.x86_64
- 处理器:
40core(Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz)
- 内存:
128GB
,两个NUMA node
min_free_kbytes
解释
在我的系统上,其值如下:
|
|
我们先看其官方解释:
|
|
从上面的解释中主要有如下两个点:
- 代表系统所保留空闲内存的最低限
- 用于计算影响内存回收的三个参数
watermark[min/low/high]
系统所保留空闲内存的最低限
在系统初始化时会根据内存大小计算一个默认值,计算规则是:
|
|
lowmem_kbytes
可以认为是系统的内存大小。精确的算法是:lowmem_kbytes
等于所有zone
中managed-high
之和。
在我的系统上各个zone
的page
个数如下:
zone | managed | min | low | high | managed - high |
---|---|---|---|---|---|
dma | 3976 | 2 | 3 | 3 | 3973 |
dma32 | 354201 | 242 | 302 | 363 | 353838 |
normal | 15991024 | 10962 | 13702 | 16443 | 15974581 |
normal | 16514229 | 11320 | 14150 | 16980 | 16497249 |
total | 32863430 | 22526 | 28157 | 33789 | 32829641 |
结合上面的算法:
|
|
另外,计算出来的值有最小最大限制,最小为128K
,最大为64M
。
可以看出,min_free_kbytes
随着内存的增大不是线性增长,注释里也提到了原因:because network bandwidth does not increase linearly with machine size。随着内存的增大,没有必要也线性的预留出过多的内存,能保证紧急时刻的使用量便足矣。
这里计算出的45837
是在内存大小为128G
的服务器上的min_free_kbytes
的初始值。但实际上该服务上min_free_kbytes
的值为90112
,显然超过了最大的64M
。
|
|
这是为什么呢?经过查看内核源代码,发现min_free_kbytes
根据如上算法初始化后,如果系统支持大页,会在set_recommended_min_free_kbytes
函数中根据情况调整该值:
|
|
用于计算影响内存回收的三个参数 watermark[min/low/high]
watermark[high] > watermark [low] > watermark[min]
,各个zone
各一套。
在系统空闲内存低于 watermark[low]
时,开始启动内核线程kswapd
进行内存回收,直到该zone
的空闲内存数量达到watermark[high]
后停止回收。如果上层申请内存的速度太快,导致空闲内存降至watermark[min]
后,内核就会进行direct reclaim
(直接回收),即直接在应用程序的进程上下文中进行回收,再用回收上来的空闲页满足内存申请,因此实际会阻塞应用程序,带来一定的响应延迟,而且可能会触发系统OOM
。这是因为watermark[min]
以下的内存属于系统的自留内存,用以满足特殊使用,所以不会给用户态的普通申请来用。
三个watermark的计算方法:
watermark[min] = min_free_kbytes
换算为page
单位即可,假设为min_free_pages
。(因为是每个zone
各有一套watermark
参数,实际计算效果是根据各个zone
大小所占内存总大小的比例,而算出来的per zone min_free_pages
)
watermark[low] = watermark[min] * 5 / 4
watermark[high] = watermark[min] * 3 / 2
所以中间的buffer
量为 :
|
|
因为min_free_kbytes = 4* sqrt(lowmem_kbytes)
,也可以看出中间的buffer
量也是跟内存的增长速度成开方关系。
我们计算一下当前系统上的各个zone
的值水位值:
min_free_kbytes
的值为90112
,换算成page
数为:22528
,即系统上所有zone
的watermark[min]
总共为22528
。- 系统上所有
zone
的总的managed
为:32863430
,计算出下表:
zone | managed | 比例 | min | low = 1.25*min |
high=1.5*min |
---|---|---|---|---|---|
DMA | 3976 | 3976/32863430 | 2 | 2.5 | 3 |
DMA32 | 354201 | 354201/32863430 | 242 | 302.50 | 363 |
NORMAL | 15991024 | 15991024/32863430 | 10961 | 13701.25 | 16441.5 |
NORMAL | 16514229 | 16514229/32863430 | 11320 | 14150.00 | 16980.0 |
Total | 32863430 |
可以通过/proc/zoneinfo
查看每个zone
的watermark
|
|
min_free_kbytes
大小的影响
min_free_kbytes
设的越大,watermark
的线越高,同时三个线之间的buffer
量也相应会增加。这意味着会较早的启动kswapd
进行回收,且会回收上来较多的内存(直至watermark[high]
才会停止),这会使得系统预留过多的空闲内存,从而在一定程度上降低了应用程序可使用的内存量。极端情况下设置min_free_kbytes
接近内存大小时,留给应用程序的内存就会太少而可能会频繁地导致OOM
的发生。
min_free_kbytes
设的过小,则会导致系统预留内存过小。kswapd
回收的过程中也会有少量的内存分配行为(会设上PF_MEMALLOC
)标志,这个标志会允许kswapd
使用预留内存;另外一种情况是被OOM
选中杀死的进程在退出过程中,如果需要申请内存也可以使用预留部分。这两种情况下让他们使用预留内存可以避免系统进入deadlock
状态。