内存管理参数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状态。