广告
返回顶部
首页 > 资讯 > 精选 >如何理解kswapd的低水位min_free_kbytes
  • 122
分享到

如何理解kswapd的低水位min_free_kbytes

2023-06-05 21:06:12 122人浏览 八月长安
摘要

这篇文章给大家介绍如何理解kswapd的低水位min_free_kbytes,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1. min_free_kbytes先看官方解释:This is used to force t

这篇文章给大家介绍如何理解kswapd的低水位min_free_kbytes,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

1. min_free_kbytes

先看官方解释:
This is used to force the linux VM to keep a minimum number of kilobytes free. The VM uses this number to compute a watermark[WMARK_MIN] value for each lowmem zone in the system. Each lowmem zone gets a number of reserved free pages based proportionally on its size.
Some minimal amount of memory is needed to satisfy PF_MEMALLOC allocations; if you set this to lower than 1024KB, your system will become subtly broken, and prone to deadlock under high loads.
Setting this too high will OOM your Machine instantly.
解释已经很清楚了,主要有以下几个关键点:

1. 代表系统所保留空闲内存的最低限。

在系统初始化时会根据内存大小计算一个默认值,计算规则是:
min_free_kbytes = sqrt(lowmem_kbytes * 16) = 4 * sqrt(lowmem_kbytes)(注:lowmem_kbytes即可认为是系统内存大小)
另外,计算出来的值有最小最大限制,最小为128K,最大为64M。
可以看出,min_free_kbytes随着内存的增大不是线性增长,comments里提到了原因“because network bandwidth does not increase linearly with machine size”。随着内存的增大,没有必要也线性的预留出过多的内存,能保证紧急时刻的使用量便足矣。

2.min_free_kbytes的主要用途是计算影响内存回收的三个参数 watermark[min/low/high]

1) watermark[high] > watermark [low] > watermark[min],各个zone各一套

2)在系统空闲内存低于 watermark[low]时,开始启动内核线程kswapd进行内存回收(每个zone一个),直到该zone的空闲内存数量达到watermark[high]后停止回收。如果上层申请内存的速度太快,导致空闲内存降至watermark[min]后,内核就会进行direct reclaim(直接回收),即直接在应用程序的进程上下文中进行回收,再用回收上来的空闲页满足内存申请,因此实际会阻塞应用程序,带来一定的响应延迟,而且可能会触发系统OOM。这是因为watermark[min]以下的内存属于系统的自留内存,用以满足特殊使用,所以不会给用户态的普通申请来用。

3)三个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量为 high - low = low - min = per_zone_min_free_pages * 1/4。因为min_free_kbytes = 4* sqrt(lowmem_kbytes),也可以看出中间的buffer量也是跟内存的增长速度成开方关系。

4)可以通过/proc/zoneinfo查看每个zone的watermark
例如:

node 0, zone      DMApages free     3960       min      65       low      81       high     97

min_free_kbytes大小的影响
min_free_kbytes设的越大,watermark的线越高,同时三个线之间的buffer量也相应会增加。这意味着会较早的启动kswapd进行回收,且会回收上来较多的内存(直至watermark[high]才会停止),这会使得系统预留过多的空闲内存,从而在一定程度上降低了应用程序可使用的内存量。极端情况下设置min_free_kbytes接近内存大小时,留给应用程序的内存就会太少而可能会频繁地导致OOM的发生。
min_free_kbytes设的过小,则会导致系统预留内存过小。kswapd回收的过程中也会有少量的内存分配行为(会设上PF_MEMALLOC)标志,这个标志会允许kswapd使用预留内存;另外一种情况是被OOM选中杀死的进程在退出过程中,如果需要申请内存也可以使用预留部分。这两种情况下让他们使用预留内存可以避免系统进入deadlock状态。

2. lowmem_reserve_ratio

官方解释:

For some specialised workloads on highmem machines it is dangerous for the kernel to allow process memory to be allocated from the "lowmem" zone. This is because that memory could then be pinned via the mlock() system call, or by unavailability of swapspace.
And on large highmem machines this lack of reclaimable lowmem memory can be fatal.
So the Linux page allocator has a mechanism which prevents allocations which could use highmem from using too much lowmem. This means that a certain amount of lowmem is defended from the possibility of being captured into pinned user memory.
The `lowmem_reserve_ratio' tunable determines how aggressive the kernel is in defending these lower zones.
If you have a machine which uses highmem or ISA DMA and your applications are using mlock(), or if you are running with no swap then you probably should change the lowmem_reserve_ratio setting.

作用
除了min_free_kbytes会在每个zone上预留一部分内存外,lowmem_reserve_ratio是在各个zone之间进行一定的防卫预留,主要是防止高端zone在没内存的情况下过度使用低端zone的内存资源。
例如现在常见的一个node的机器有三个zone: DMA,DMA32和NORMAL。DMA和DMA32属于低端zone,内存也较小,如96G内存的机器两个zone总和才1G左右,NORMAL就相对属于高端内存(现在一般没有HIGH zone),而且数量较大(>90G)。低端内存有一定的特殊作用比如发生DMA时只能分配DMA zone的低端内存,因此需要在 尽量可以使用高端内存时 而 不使用低端内存,同时防止高端内存分配不足的时候抢占稀有的低端内存。

  1. 计算方法

cat /proc/sys/vm/lowmem_reserve_ratio256     256     32

内核利用上述的protection数组计算每个zone的预留page量,计算出来也是数组形式,从/proc/zoneinfo里可以查看:

Node 0, zone      DMA pages free     1355       min      3       low      3       high     4       :       :   numa_other   0       protection: (0, 2004, 2004, 2004)       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pagesets   cpu: 0 pcp: 0       :

在进行内存分配时,这些预留页数值和watermark相加来一起决定现在是满足分配请求,还是认为空闲内存量过低需要启动回收。
例如,如果一个normal区(index = 2)的页申请来试图分配DMA区的内存,且现在使用的判断标准是watermark[low]时,内核计算出 page_free = 1355,而watermark + protection[2] = 3 + 2004 = 2007 > page_free,则认为空闲内存太少而不予以分配。如果分配请求本就来自DMA zone,则 protection[0] = 0会被使用,而满足分配申请。
zone[i] 的 protection[j] 计算规则如下:

(i < j): zone[i]->protection[j] = (total sums of present_pages from zone[i+1] to zone[j] on the node)   / lowmem_reserve_ratio[i];(i = j):  (should not be protected. = 0;(i > j):  (not necessary, but looks 0)

默认的 lowmem_reserve_ratio[i] 值是:

   256 (if zone[i] means DMA or DMA32 zone)   32  (others).

从上面的计算规则可以看出,预留内存值是ratio的倒数关系,如果是256则代表 1/256,即为 0.39% 的高端zone内存大小。
如果想要预留更多页,应该设更小一点的值,最小值是1(1/1 -> 100%)。

  1. 和min_free_kbytes(watermark)的配合示例
    下面是一段某线上服务器(96G)内存申请失败时打印出的log:

  2. [38905.295014] java: page allocation failure. order:1, mode:0x20, zone 2[38905.295020] Pid: 25174, comm: java Not tainted 2.6.32-220.23.1.tb750.el5.x86_64 #1...[38905.295348] active_anon:5730961 inactive_anon:216708 isolated_anon:0[38905.295349]  active_file:2251981 inactive_file:15562505 isolated_file:0[38905.295350]  unevictable:1256 dirty:790255 writeback:0 unstable:0[38905.295351]  free:113095 slab_reclaimable:577285 slab_unreclaimable:31941[38905.295352]  mapped:7816 shmem:4 pagetables:13911 bounce:0[38905.295355] Node 0 DMA free:15796kB min:4kB low:4kB high:4kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB  isolated(anon):0kB isolated(file):0kB present:15332kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes[38905.295365] lowmem_reserve[]: 0 1951 96891 96891[38905.295369] Node 0 DMA32 free:380032kB min:800kB low:1000kB high:1200kB active_anon:46056kB inactive_anon:10876kB active_file:15968kB inactive_file:129772kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:1998016kB mlocked:0kB dirty:20416kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:11716kB slab_unreclaimable:160kB kernel_stack:176kB pagetables:112kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:576 all_unreclaimable? no[38905.295379] lowmem_reserve[]: 0 0 94940 94940[38905.295383] Node 0 Normal free:56552kB min:39032kB low:48788kB high:58548kB active_anon:22877788kB inactive_anon:855956kB active_file:8991956kB inactive_file:62120248kB unevictable:5024kB isolated(anon):0kB isolated(file):0kB present:97218560kB mlocked:5024kB dirty:3140604kB writeback:0kB mapped:31264kB shmem:16kB slab_reclaimable:2297424kB slab_unreclaimable:127604kB kernel_stack:12528kB pagetables:55532kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no[38905.295393] lowmem_reserve[]: 0 0 0 0[38905.295396] Node 0 DMA: 1*4kB 2*8kB 0*16kB 1*32kB 2*64kB 0*128kB 1*256kB 0*512kB 1*1024kB 1*2048kB 3*4096kB = 15796kB[38905.295405] Node 0 DMA32: 130*4kB 65*8kB 75*16kB 72*32kB 95*64kB 22*128kB 10*256kB 7*512kB 4*1024kB 2*2048kB 86*4096kB = 380032kB[38905.295414] Node 0 Normal: 12544*4kB 68*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 1*4096kB = 54816kB[38905.295423] 17816926 total pagecache pages

1)从第一行log“order:1, mode:0x20”可以看出来是GFP_ATOMIC类型的申请,且order = 1(page = 2 )

2)第一次内存申请尝试

在__alloc_pages_nodemask()里,首先调用 get_page_from_freelist() 尝试第一次申请,使用的标志位是 ALLOC_WMARK_LOW|ALLOC_CPUSET,它会对每个zone都做 zone_watermark_ok()的检查,使用的就是传进的watermark[low]阈值。
    在zone_watermark_ok()里会考虑z->lowmem_reserve[],导致在normal上的申请不会落到低端zone。比如对于DMA32:
free pages = 380032KB = 95008 pages < low(1000KB = 250 pages) + lowmem_reservenormal = 95190
所以就认为DMA32也不平不ok,同理更用不了DMA的内存。
而对于normal自己内存来说,free pages = 56552 KB = 14138 pages,也不用考虑lowmem_reserve(0),但这时还会考虑申请order(1),减去order 0的12544个page后只剩 14138 - 12544 = 1594,也小于 low / 2 = (48788KB=12197pages) / 2 = 6098 pages。
所以初次申请尝试失败,进入__alloc_pages_slowpath() 尝试进行更为积极一些的申请。

3)第二次内存申请尝试
__alloc_pages_slowpath()首先是通过 gfp_to_alloc_flags() 修改alloc_pages,设上更为强硬的标志位。这块根据原来的GFP_ATOMIC会设上 ALLOC_WMARK_MIN | ALLOC_HARDER | ALLOC_HIGH。但注意的是不会设上 ALLOC_NO_WATERMARKS 标志位。这个标志位不再判断zone的水位限制,属于优先级最高的申请,可以动用所有的reserve内存,但条件是(!in_interrupt() && ((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE)))),即要求不能在中断上下文,且是正在进行回收(例如kswapd)或者正在退出的进程。
    之后进入拿着新的alloc_pages重新进入get_page_from_pagelist() 尝试第二次申请,虽然有了 ALLOC_HARDER和ALLOC_HIGH,但是不幸的是在3个zone的zone_watermark_ok检查中还是都无法通过,例如对于DMA32:
free pages = 380032KB = 95008 pages
因为设上了ALLOC_HIGH 所以会将得到的watermark[min]减半,即min = min/2 = 800K / 2 = 400K = 100pages
而又因为设上了ALLOC_HARDER,会再将min砍去1/4,即min = 3 * min / 4 = 100 pages * 3 / 4 = 75 pages
即便如此,min(75 pages) + lowmem_reservenormal = 95015,仍大于free pages,仍认为无法分配内存,同理DMA也不不成功,而normal中 free pages里连续8K的页太少也无法满足分配
    第二次失败后,由于没有ALLOC_NO_WATERMARK也不会进入__alloc_pages_high_priority 进行最高优先级的申请,同时由于是GFP_ATOMIC类型的分配不能阻塞回收或者进入OOM,因此就以申请失败告终。
遇到此种情况可以适当调高 min_free_kbytes 使kswapd较早启动回收,使系统一直留有较多的空闲内存,同时可以适度降低 lowmem_reserve_ratio(可选),使得内存不足的情况下(主要是normal zone)可以借用DMA32/DMA的内存救急(注意不能也不能过低)。

关于如何理解kswapd的低水位min_free_kbytes就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: 如何理解kswapd的低水位min_free_kbytes

本文链接: https://www.lsjlt.com/news/244647.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何理解kswapd的低水位min_free_kbytes
    这篇文章给大家介绍如何理解kswapd的低水位min_free_kbytes,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1. min_free_kbytes先看官方解释:This is used to force t...
    99+
    2023-06-05
  • 如何理解低代码的兴起
    这篇文章主要讲解了“如何理解低代码的兴起”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解低代码的兴起”吧!低代码是一种近些年兴起的企业软件快速开发技术...
    99+
    2022-10-19
  • 如何解析Oracle 高水位(HWM)对select性能的影响
    这篇文章将为大家详细讲解有关如何解析Oracle 高水位(HWM)对select性能的影响,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。 不知道大家有没有...
    99+
    2022-10-19
  • 如何理解Socket的低层次Java网络编程
    这篇文章将为大家详细讲解有关如何理解Socket的低层次Java网络编程,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Socket的低层次Java网络编程1 Socket通讯网络上的两个程序...
    99+
    2023-06-02
  • 如何理解CSS编程中的定位
    这篇文章主要介绍“如何理解CSS编程中的定位”,在日常操作中,相信很多人在如何理解CSS编程中的定位问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解CSS编程中的定位”...
    99+
    2022-10-19
  • 如何理解页面元素的绝对定位和相对定位
    这篇文章主要介绍“如何理解页面元素的绝对定位和相对定位”,在日常操作中,相信很多人在如何理解页面元素的绝对定位和相对定位问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解页面元素的绝对定位和相对定位”的疑...
    99+
    2023-06-08
  • 如何理解Web前端CSS的定位机制
    本篇内容主要讲解“如何理解Web前端CSS的定位机制”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解Web前端CSS的定位机制”吧!定位(position)顾名思义,你想定哪就定哪;元素的...
    99+
    2023-06-03
  • 如何理解Python嵌入较低层次中的常用两种函数
    这期内容当中小编将会给大家带来有关如何理解Python嵌入较低层次中的常用两种函数,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。如果需要在C程序中用Python脚本传递参数,或者获得Python脚本的返回...
    99+
    2023-06-17
  • 如何设置虚拟内存解决物理内存较低的问题
    当我们在运行一些大型的软件,或者是刚刚退出游戏的时候经常会提示“你的虚拟内存过低”的提示,出现这种情况一般是:一:你的物理内存比较小,运行大的软件比较吃力;二:你运行了许多窗口或者是游戏的时候物理...
    99+
    2023-05-26
    虚拟内存 问题 内存 物理
  • 如何理解Shell脚本中的位置变量参数
    这篇文章主要介绍“如何理解Shell脚本中的位置变量参数”,在日常操作中,相信很多人在如何理解Shell脚本中的位置变量参数问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Shell脚本中的位置变量参数...
    99+
    2023-06-09
  • 如何使用使用python+opencv解析视频并处理视频中的水印
    本篇内容主要讲解“如何使用使用python+opencv解析视频并处理视频中的水印”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何使用使用python+opencv解析视频并处理视频中的水印”...
    99+
    2023-06-02
  • 如何理解DIV定位单元中三大元素的控制
    如何理解DIV定位单元中三大元素的控制,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。你对DIV定位单元的控制方式是否熟悉,这里和大家分享一下,...
    99+
    2022-10-19
  • 如何理解Shell编程中的特殊变量之位置变量
    本篇内容介绍了“如何理解Shell编程中的特殊变量之位置变量”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!$0 获得当前脚本的文件名,包括路...
    99+
    2023-06-09
  • 如何从Go语言角度理解关于计算机位的问题
    这篇文章主要介绍“如何从Go语言角度理解关于计算机位的问题”,在日常操作中,相信很多人在如何从Go语言角度理解关于计算机位的问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作