写在前面

这是我第一次在知乎上发表文章,其实早在很早之前就一直有想写点东西的想法,迫于各种原因最终一直未能落实下来。最近突然看到了几位大佬写的文章,又再次让我有了写点东西的想法。作为自己学习的一个总结,当然如果我写的东西能对大家有帮助就更好了。

概述

作为一名Linux系统运维工程师,相信大家经常会遇到OOM的情况,那么什么是OOM?OOM的日志怎么解读?本文我们会介绍这方面的技能。

按照惯例,我们在了解某个东西之前肯定需要先了解一些基础知识。

如下图,我们都知道Linux 内存将内存做了以下划分(如: Node、Zone、Page),这里我们先简单看一些内存相关的名词解释。

1. Node

什么是Node?我们先看下多路CPU是怎么工作的,如图所示是两个物理CPU,我们现在的服务器通常都会有多路CPU在一个主板上,不同的内存器件和CPU核心从属于不同的Node,每个Node都有自己的集成内存控制器。

而在Node内部,其架构类似于UMA,几个核心共享该Node的内存,并且通过IMC Bus进行不同核心之间的通信;不同Node之间则通过QPI(Quick Path Interconnect——又名CSI,Common System Interface公共系统接口,是一种可以实现芯片间直接互联的架构)进行通信。

Linux内核把物理内存按照CPU节点划分为不同的node, 每个node作为某个cpu结点的本地内存, 而作为其他CPU节点的远程内存, 而UMA结构下, 则任务系统中只存在一个内存node, 这样对于UMA结构来说, 内核把内存当成只有一个内存node节点的伪NUMA。

如何查看主机有多少个Node,执行numactl --hardware,我们可以看到node的情况,当前测试机只有一个node,node0 中包含0-3 总共四个核。

2. Zone

什么是Zone呢?其实划分Zone来管理内存也是有一定历史原因的,由于地址数据线位宽的限制,32位处理器通常最多支持4GB(未开启LPAE特性)。在4GB的地址空间中,通常内核空间只有1GB大小,因此对于大小为4GB的物理内存是无法进行一一线性映射的。Linux内核的做法就是将物理内存分成两部分,其中一部分是线性映射的。对应就是ZONE_NORMAL。剩余部分叫做高阶内存(high memory), 对应ZONE_HIGHMEM。

内存管理区的分布和架构也有关系,x86架构中,ISA设备只能访问物理内存的前16MB,所以在x86架构中会多一个ZONE_DMA的zone。在x86_64中,由于有足够大的内核空间可以线性映射物理内存,则不需要有ZONE_HIGHMEM这个zone。

常见的几个ZONE:

  1. ZONE_DMA:用于ISA设备的DMA操作,范围是0-16MB,只适用于Intel x86架构。
  2. ZONE_DMA32:用于地域4GB的内存访问的设备,如只支持32位的DMA设备。
  3. ZONE_NORMAL:4GB以后的物理内存,用于线性映射物理内存。如果内存小于4GB,则没有这个ZONE。实测低于等于4GB的时候 这个zone是有少量内存的。
  4. ZONE_HIGHMEM:用于管理高端内存。64位的系统中没有这个zone。

3. Page

虽然内存访问的最小单位是byte或者word,但MMU是以page为单位来查找页表的,page也就成了Linux中内存管理的重要单位。包括换出(swap out)、回收(relcaim)、映射等操作,都是以page为粒度的。

所以在前面提到的zone的概念中,我们可以进一步看到每个zone里面的page情况,执行 cat /proc/pagetypeinfo

这里就记录了每个Zone的page的情况,如红字对应的,从左往右依次是4kB 8kB....的page。

4. 内存分配

在内核中,内存的分配方式也有很多种,这里我们也简单介绍几个常用的方式,对于后面内存泄漏相关的问题的理解有一定帮助。

4.1 vmalloc

vmalloc是一个接口函数, 内核代码使用它来分配在虚拟内存中连续但在物理内存中不一定连续的内存。比如在模块加载时,由于内核模块数据一般比较多,linux系统中往往无法为其提供如此大块的连续内存块,就可以用vmalloc函数为其分配物理地址不连续的内存块。

4.2 slab

前面我们提到 Linux内存以页为单位进行内存管理,但是页的粒度还是太大,Linux下是4KB大小,也就是4096个字节,而kernel本身有很多数据结构时时刻刻都需要分配或者释放,这些数据的大小又往往小于4KB大小,一般只有几个几十个字节这样的大小。所以会造成内存的浪费。SLAB是一种分配器,目的就是用来解决上述问题的。

依托伙伴系统,slab 分配器则提供了小内存的分配能力(虽然也兼容大内存分配)。slab分配器从伙伴系统"批发"大内存,然后把大内存分隔成许多小块内存,一个小块内存块我们称为object, 最后把object "零售"给其他内核组件使用。主要API有kmalloc/kmem_cache_alloc。

4.3 allocpages

alloc_pages是内核中常用的分配物理内存页面的函数, 函数定义在[include/linux/gfp.h], 用于分配2^order 个连续的物理页。

需要注意的是,这部分是直接从伙伴系统申请内存,不像page fault这种申请内存,很多审计计数都是没有的,这也会导致一个问题,我们的/proc/meminfo是统计不到这部分内存的,也就会导致我们常用的free、top这种命令无法统计到这部分内存。

4.4 others

其他的内存就比如PageTable、Reserve、KernelStack。

OOM日志解析

好了,前面讲了挺多废话,我们还是先来看看OOM是什么,OOM即Out Of Memory,我们都知道Linux内存不足的时候,进程再去申请内存就很容易触发OOM机制,但这个内存不足具体是什么内存不足呢?

结合一段日志我们来看下:

Jul 25 03:30:40 mobannn kernel: java invoked oom-killer: gfp_mask=0xd0, order=2, oom_adj=0, oom_score_adj=0
Jul 25 03:30:40 mobannn kernel: java cpuset=/ mems_allowed=0
Jul 25 03:30:40 mobannn kernel: Pid: 30122, comm: java Not tainted 2.6.32-754.25.1.el6.x86_64 #1
.....省略中间部分日志
Jul 25 03:30:40 mobannn kernel: Node 0 DMA free:15752kB min:248kB low:308kB high:372kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15364kB 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
Jul 25 03:30:40 mobannn kernel: lowmem_reserve[]: 0 3000 4010 4010
Jul 25 03:30:40 mobannn kernel: Node 0 DMA32 free:1226876kB min:50372kB low:62964kB high:75556kB active_anon:1701300kB inactive_anon:0kB active_file:6996kB inactive_file:9756kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3072096kB mlocked:0kB dirty:0kB writeback:7508kB mapped:4416kB shmem:0kB slab_reclaimable:6912kB slab_unreclaimable:13176kB kernel_stack:18864kB pagetables:4568kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
Jul 25 03:30:40 mobannn kernel: lowmem_reserve[]: 0 0 1010 1010
Jul 25 03:30:40 mobannn kernel: Node 0 Normal free:21160kB min:16956kB low:21192kB high:25432kB active_anon:942108kB inactive_anon:360kB active_file:260kB inactive_file:264kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:1034240kB mlocked:0kB dirty:0kB writeback:304kB mapped:304kB shmem:376kB slab_reclaimable:6284kB slab_unreclaimable:24024kB kernel_stack:7632kB pagetables:5300kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
Jul 25 03:30:40 mobannn kernel: lowmem_reserve[]: 0 0 0 0
Jul 25 03:30:40 mobannn kernel: Node 0 DMA: 2*4kB 2*8kB 1*16kB 1*32kB 1*64kB 0*128kB 1*256kB 0*512kB 1*1024kB 1*2048kB 3*4096kB = 15752kB
Jul 25 03:30:40 mobannn kernel: Node 0 DMA32: 191481*4kB 57619*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 1226876kB
Jul 25 03:30:40 mobannn kernel: Node 0 Normal: 5250*4kB 20*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 21160kB
Jul 25 03:30:40 mobannn kernel: 4513 total pagecache pages
Jul 25 03:30:40 mobannn kernel: 0 pages in swap cache
Jul 25 03:30:40 mobannn kernel: Swap cache stats: add 0, delete 0, find 0/0
Jul 25 03:30:40 mobannn kernel: Free swap  = 0kB
Jul 25 03:30:40 mobannn kernel: Total swap = 0kB
Jul 25 03:30:40 mobannn kernel: 1048575 pages RAM
Jul 25 03:30:40 mobannn kernel: 34487 pages reserved
Jul 25 03:30:40 mobannn kernel: 6052 pages shared
Jul 25 03:30:40 mobannn kernel: 685379 pages non-shared
...省略中间大量进程信息
Jul 25 03:30:40 mobannn kernel: [ 3637]     0  3637   201397      808   1       0             0 aliyun-service
Jul 25 03:30:40 mobannn kernel: [ 3784]     0  3784     4457      200   0       0             0 assist_daemon
Jul 25 03:30:40 mobannn kernel: [16680]     0 16680     8916      450   0       0             0 AliYunDunUpdate
Jul 25 03:30:40 mobannn kernel: [16721]     0 16721    65420     3218   0       0             0 AliYunDun
Jul 25 03:30:40 mobannn kernel: Out of memory: Kill process 29598 (java) score 628 or sacrifice child
Jul 25 03:30:40 mobannn kernel: Killed process 29598, UID 505, (java) total-vm:5232064kB, anon-rss:2541632kB, file-rss:1912kB

首先我们需要对这段日志解读一下

Jul 25 03:30:40 mobannn kernel: java invoked oom-killer: gfp_mask=0xd0, order=2, oom_adj=0, oom_score_adj=0

这里的信息可以看到我们是有个java的进程触发了oom,当时这个java的进程正在申请order=2的page,通过上一章节我们介绍的Zone部分的内容,我们可以知道order=2其实就是对应16kB的page。也就是说这个时候进程正在申请一个16kB的page,然后触发了oom。

Jul 25 03:30:40 mobannn kernel: java cpuset=/ mems_allowed=0

这段日志表示这是根组(cgroup的概念),也就是说他并没有使用cgroup,而是直接用的根组。结合上面两条日志可以大概推断可能当时16kB的page不足了。

Jul 25 03:30:40 mobannn kernel: Node 0 DMA free:15752kB min:248kB low:308kB high:372kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15364kB 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
Jul 25 03:30:40 mobannn kernel: lowmem_reserve[]: 0 3000 4010 4010
Jul 25 03:30:40 mobannn kernel: Node 0 DMA32 free:1226876kB min:50372kB low:62964kB high:75556kB active_anon:1701300kB inactive_anon:0kB active_file:6996kB inactive_file:9756kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3072096kB mlocked:0kB dirty:0kB writeback:7508kB mapped:4416kB shmem:0kB slab_reclaimable:6912kB slab_unreclaimable:13176kB kernel_stack:18864kB pagetables:4568kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
Jul 25 03:30:40 mobannn kernel: lowmem_reserve[]: 0 0 1010 1010
Jul 25 03:30:40 mobannn kernel: Node 0 Normal free:21160kB min:16956kB low:21192kB high:25432kB active_anon:942108kB inactive_anon:360kB active_file:260kB inactive_file:264kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:1034240kB mlocked:0kB dirty:0kB writeback:304kB mapped:304kB shmem:376kB slab_reclaimable:6284kB slab_unreclaimable:24024kB kernel_stack:7632kB pagetables:5300kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
Jul 25 03:30:40 mobannn kernel: lowmem_reserve[]: 0 0 0 0
Jul 25 03:30:40 mobannn kernel: Node 0 DMA: 2*4kB 2*8kB 1*16kB 1*32kB 1*64kB 0*128kB 1*256kB 0*512kB 1*1024kB 1*2048kB 3*4096kB = 15752kB
Jul 25 03:30:40 mobannn kernel: Node 0 DMA32: 191481*4kB 57619*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 1226876kB
Jul 25 03:30:40 mobannn kernel: Node 0 Normal: 5250*4kB 20*8kB 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 21160kB

oom的日志还是非常详细的,贴心的将每个Zone的内存分布情况也给我们打印出来了,这里我们可以直观的查看到每个Zone中的内存分布情况,可以看到Normal 和DMA32中,16kB的page都是0,在Linux内核中 64位的机器申请内存(这个针对普通进程而言,除一些驱动等特殊情况)的时候内核会优先分配Normal区的内存,如果不足会尝试分配DMA32中的内存,因为内核会优先保留DMA32区的内存用于一些特殊情况。

这个案例的日志可以看到不管是Normal还是DMA32 的16kB 页都是0,所以会申请失败,当然这个过程中内核应该也会存在一个内存回收的动作的,比如上面日志第5行,我们可以看到当时Normal区的free是小于low的,这个时候会唤醒kswapd 进行内存回收,这里由于没有记录每个CPU的堆栈信息,可能看不到这个动作。

这里内存回收有两种情况,一种是异步回收 还未来得及回收就触发了oom机制 强制回收内存。另一种是回收后仍然16kB的page不足,导致oom。

这里我们以这个案例,简单介绍了一下oom的日志中的一些关键信息,可以根据这些关键信息大致判断当时触发oom的原因。下面我们会再总结一些常见的oom触发场景。

OOM触发原因和排查

内存碎片

1) 说明

  • 外部碎片

外部碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。

产生的原因:外部碎片是出于任何已分配区域或页面外部的空闲存储块。这些存储块的总和可以满足当前申请的长度要求,但是由于它们的地址不连续或其他原因,使得系统无法满足当前申请。

  • 内部碎片

内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被利用的空间。

产生原因:由于采用固定大小的内存分区,当一个进程不能完全使用分给它的固定内存区域时就产生了内部碎片,通常内部碎片难以完全避免。

2) 如何排查

比较典型的表现就是高阶内存都为0了,但节点总的剩余内存还是有一定量的。

这个也就是上面提到的案例,order=2的page申请失败

3) 解决方案

  1. 同时需要排查有没有业务进程有占用过多内存的情况,如果业务内存使用量符合预期,那么需要考虑升级内存
  2. 定期触发内存规整动作,触发命令:echo 1 > /proc/sys/vm/compact_memory。
  3. 定期释放cache,但需要注意释放cache会有一定性能抖动,请合理规划执行时间窗口,命令:echo 3 > /proc/sys/vm/drop_caches。
  4. 调整vm.min_free_kbytes参数,也就是min水位线,推荐设置为总内存的2%,当内存资源快要不足的时候,提前进入内存异步回收,降低因为异步回收不及时导致的oom概率。

全局内存的使用率过高

1) 说明

由于实例的空闲内存低于内存最低水位线,无法通过内存回收机制解决内存不足的问题,这种情况也会触发OOM Killer。

2) 如何排查

limit of host表示实例的全局内存出现了不足。在日志记录的数据中,空闲内存(free)已经低于了内存最低水位线(low)

[二 8月  2 10:49:59 2022] Task in /user.slice killed as a result of limit of host
[二 8月  2 10:49:59 2022] Mem-Info:
[二 8月  2 10:49:59 2022] active_anon:930 inactive_anon:1898432 isolated_anon:0
 active_file:105 inactive_file:0 isolated_file:0
 unevictable:0 dirty:0 writeback:0 unstable:0
 slab_reclaimable:14649 slab_unreclaimable:14308
 mapped:54 shmem:163 pagetables:7659 bounce:0
 free:25434 free_pcp:1585 free_cma:0
[二 8月  2 10:49:59 2022] Node 0 active_anon:3720kB inactive_anon:7593728kB active_file:160kB inactive_file:56kB unevictable:0kB isolated(anon):0kB isolated(file):0kB mapped:216kB dirty:0kB writeback:0kB shmem:652kB shmem_thp: 0kB shmem_pmdmapped: 0kB anon_thp: 5107712kB writeback_tmp:0kB unstable:0kB all_unreclaimable? yes
[二 8月  2 10:49:59 2022] Node 0 DMA free:15908kB min:132kB low:164kB high:196kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB writepending:0kB present:15992kB managed:15908kB mlocked:0kB kernel_stack:0kB pagetables:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB
[二 8月  2 10:49:59 2022] lowmem_reserve[]: 0 2789 7708 7708 7708
[二 8月  2 10:49:59 2022] Node 0 DMA32 free:43624kB min:24408kB low:30508kB high:36608kB active_anon:0kB inactive_anon:2819380kB active_file:4kB inactive_file:940kB unevictable:0kB writepending:0kB present:3129216kB managed:2867040kB mlocked:0kB kernel_stack:0kB pagetables:0kB bounce:0kB free_pcp:3552kB local_pcp:316kB free_cma:0kB
[二 8月  2 10:49:59 2022] lowmem_reserve[]: 0 0 4918 4918 4918
[二 8月  2 10:49:59 2022] Node 0 Normal free:42708kB min:43036kB low:53792kB high:64548kB active_anon:3720kB inactive_anon:4774348kB active_file:260kB inactive_file:0kB unevictable:0kB writepending:0kB present:5242880kB managed:5043008kB mlocked:0kB kernel_stack:5456kB pagetables:30636kB bounce:0kB free_pcp:3776kB local_pcp:496kB free_cma:0kB
[二 8月  2 10:49:59 2022] lowmem_reserve[]: 0 0 0 0 0
[二 8月  2 10:49:59 2022] Node 0 DMA: 1*4kB (U) 0*8kB 0*16kB 1*32kB (U) 2*64kB (U) 1*128kB (U) 1*256kB (U) 0*512kB 1*1024kB (U) 1*2048kB (M) 3*4096kB (M) = 15908kB
[二 8月  2 10:49:59 2022] Node 0 DMA32: 33*4kB (UM) 14*8kB (UM) 17*16kB (UM) 9*32kB (UM) 5*64kB (U) 1*128kB (U) 10*256kB (UM) 10*512kB (UM) 4*1024kB (M) 1*2048kB (U) 7*4096kB (UM) = 43748kB
[二 8月  2 10:49:59 2022] Node 0 Normal: 479*4kB (UE) 231*8kB (UME) 209*16kB (UE) 286*32kB (UME) 139*64kB (UME) 56*128kB (UME) 20*256kB (UME) 4*512kB (UME) 4*1024kB (UM) 0*2048kB 0*4096kB = 43588kB
[二 8月  2 10:49:59 2022] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
[二 8月  2 10:49:59 2022] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
[二 8月  2 10:49:59 2022] 289 total pagecache pages
[二 8月  2 10:49:59 2022] 0 pages in swap cache
[二 8月  2 10:49:59 2022] Swap cache stats: add 0, delete 0, find 0/0
[二 8月  2 10:49:59 2022] Free swap  = 0kB
[二 8月  2 10:49:59 2022] Total swap = 0kB
[二 8月  2 10:49:59 2022] 2097022 pages RAM
[二 8月  2 10:49:59 2022] 0 pages HighMem/MovableOnly
[二 8月  2 10:49:59 2022] 115533 pages reserved
[二 8月  2 10:49:59 2022] 0 pages cma reserved
[二 8月  2 10:49:59 2022] 0 pages hwpoisoned
[二 8月  2 10:49:59 2022] Tasks state (memory values in pages):
....省略大量中间日志
[二 8月  2 10:49:59 2022] [   2350]     0  2350    28390      144    73728        0             0 bash
[二 8月  2 10:49:59 2022] [   2398]     0  2398   255370    25519  3686400        0             0 node
[二 8月  2 10:49:59 2022] [   2409]     0  2409   194950     4830   724992        0             0 node
[二 8月  2 10:49:59 2022] [   2566]     0  2566   149862     2726   700416        0             0 node
[二 8月  2 10:49:59 2022] [   2578]     0  2578   250611    37568  5263360        0             0 node
[二 8月  2 10:49:59 2022] [   2721]     0  2721    39214      332   344064        0             0 sshd
[二 8月  2 10:49:59 2022] [   2723]     0  2723    37358      477   151552        0             0 zsh
[二 8月  2 10:49:59 2022] [   2806]     0  2806    39214      332   352256        0             0 sshd
[二 8月  2 10:49:59 2022] [   2808]     0  2808    37357      475   151552        0             0 zsh
[二 8月  2 10:49:59 2022] [   4631]     0  4631  1812544  1761720 14327808        0             0 redis-server
[二 8月  2 10:49:59 2022] Out of memory: Kill process 4631 (redis-server) score 890 or sacrifice child
[二 8月  2 10:49:59 2022] Killed process 4631 (redis-server) total-vm:7250176kB, anon-rss:7046880kB, file-rss:0kB, shmem-rss:0kB
[二 8月  2 10:49:59 2022] oom_reaper: reaped process 4631 (redis-server), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

3) 解决方案

  1. 检查确认业务应用有无内存溢出等异常情况;有没有异常进程(中毒之类的)消耗内存
  2. 业务确认正常的话,这种情况建议升级内存,开启swap可以有一定缓解 但性能开销会比较大。

cgroup内存使用达到上限

1) 说明

cgroups 是Linux内核提供的一种可以限制单个进程或者多个进程所使用资源的机制,可以对 cpu,内存等资源实现精细化的控制,目前云原生就使用了 cgroups 提供的资源限制能力来完成cpu,内存等部分的资源控制。

2) 如何排查

比较典型的就是下面这种,会直接打印出来Task in xxxx killed as a result of limit of xxxx

这里也就明确告诉告诉我们usage已经触达了cgroup的limit

3) 解决方案

  1. 同样是先排查应用层面是否是需要这么大的内存
  2. 如果应用层面没有优化空间,那么就需要调整cgroup的上限,容器场景一般需要修改pod里面的limit信息,如果没有容器场景,单独使用的话可以这样去修改指定cgroup的内存限制 echo value > /sys/fs/cgroup/memory/${cgroup}/memory.limit_in_bytes

内存节点(Node)的内存不足

1) 说明

NUMA的架构中有Node的概念,当某个Node上的内存不足,而应用恰好在这个Node申请内存的时候就可能出现无法申请成功,触发oom。

2) 如何排查

如下日志记录的出现OOM Killer场景示例中,部分日志记录说明:

  • limit of host表示内存节点的内存出现了不足。
  • 实例存在Node 0和Node 1两个内存节点。
  • 内存节点Node 1的空闲内存(free)低于内存最低水位线(low)。
  • 实例的空闲内存还有大量剩余(free:4111496)。
[Sat Sep 11 09:46:24 2021] main invoked oom-killer: gfp_mask=0x62****(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), nodemask=(null), order=0, oom_score_adj=0
[Sat Sep 11 09:46:24 2021] main cpuset=mm_cpuset mems_allowed=1
[Sat Sep 11 09:46:24 2021] Task in / killed as a result of limit of host
[Sat Sep 11 09:46:24 2021] Mem-Info:
[Sat Sep 11 09:46:24 2021] active_anon:172 inactive_anon:4518735 isolated_anon:
    free:4111496 free_pcp:1 free_cma:0
[Sat Sep 11 09:46:24 2021] Node 1 Normal free:43636kB min:45148kB low:441424kB high:837700kB
[Sat Sep 11 09:46:24 2021] Node 1 Normal: 856*4kB (UME) 375*8kB (UME) 183*16kB (UME) 184*32kB (UME) 87*64kB (ME) 45*128kB (UME) 16*256kB (UME) 5*512kB (UE) 14*1024kB (UME) 0     *2048kB 0*4096kB = 47560kB
[Sat Sep 11 09:46:24 2021] Node 0 hugepages_total=360 hugepages_free=360 hugepages_surp=0 hugepages_size=1048576kB
[Sat Sep 11 09:46:24 2021] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
[Sat Sep 11 09:46:24 2021] Node 1 hugepages_total=360 hugepages_free=360 hugepages_surp=0 hugepages_size=1048576kB
[Sat Sep 11 09:46:25 2021] Node 1 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB

3) 解决方案

内存节点(Node)的内存不足导致的OOM Killer,您需要重新配置cpuset.mems接口的值,使cgroup能够合理使用内存节点的内存。配置cpuset.mems的命令说明如下:

  1. 运行以下命令,确定系统中内存节点(Node)的数量信息。

cat /proc/buddyinfo

2. 配置cpuset.mems。

echo value > /sys/fs/cgroup/cpuset/test/cpuset.mems

其中,value为对应的内存节点号。

例如,系统中存在三个Node,分别为Node 0、Node 1、Node 2。您需要让cgroup使用Node 0和Node 2两个节点的内存。则value取值为0,2。

发表评论

邮箱地址不会被公开。 必填项已用*标注