OOM Killer(Out of Memory Killer)是Linux内核在系统内存严重不足时,强行释放进程内存的一种机制。本文介绍Alibaba Cloud Linux操作系统出现OOM Killer的可能原因,并提供多种解决方案。

问题现象

Alibaba Cloud Linux操作系统在实例全局内存或实例内cgroup的内存不足时,会先触发内存回收机制释放内存,并将这部分被释放的内存分配给其他进程。如果内存回收机制不能处理系统内存不足的情况,则系统会触发OOM Killer强制释放进程占用的内存。触发OOM Killer的部分日志信息示例如下:
565 [六 9月 11 12:24:42 2021] test invoked oom-killer: gfp_mask=0x62****(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), nodemask=(null), order=0, oom_score_adj=0
566 [六 9月 11 12:24:42 2021] test cpuset=/ mems_allowed=0
567 [六 9月 11 12:24:42 2021] CPU: 1 PID: 29748 Comm: test Kdump: loaded Not tainted 4.19.91-24.1.al7.x86_64 #1
568 [六 9月 11 12:24:42 2021] Hardware name: Alibaba Cloud Alibaba Cloud ECS, BIOS e62**** 04/01/2014

可能原因

系统出现OOM Killer表示内存不足,内存不足可以分为实例全局内存不足和实例内cgroup的内存不足。目前常见的出现OOM Killer的原因有以下几种:
原因类型 场景示例
cgroup内存使用达到上限 如下日志记录的出现OOM Killer场景示例中,进程test所在的cgroup /mm_test发生了OOM Killer。
[Wed Sep  8 18:01:32 2021] test invoked oom-killer: gfp_mask=0x240****(GFP_KERNEL), nodemask=0, order=0, oom_score_adj=0
[Wed Sep  8 18:01:32 2021] Task in /mm_test killed as a result of limit of /mm_test
[Wed Sep  8 18:01:32 2021] memory: usage 204800kB, limit 204800kB, failcnt 26
原因:cgroup /mm_test的内存使用率达到上限(200 MB)。
父cgroup内存使用达到上限 如下日志记录的出现OOM Killer场景示例中,进程test属于cgroup /mm_test/2,而发生OOM Killer的cgroup为/mm_test
[Fri Sep 10 16:15:14 2021] test invoked oom-killer: gfp_mask=0x240****(GFP_KERNEL), nodemask=0, order=0, oom_score_adj=0
[Fri Sep 10 16:15:14 2021] Task in /mm_test/2 killed as a result of limit of /mm_test
[Fri Sep 10 16:15:14 2021] memory: usage 204800kB, limit 204800kB, failcnt 1607
原因:cgroup /mm_test/2的内存使用率没有达到上限,但父cgroup /mm_test的内存使用率达到上限(200 MB)。
系统全局内存的使用率过高 如下日志记录的出现OOM Killer场景示例中,limit of host表示实例的全局内存出现了不足。在日志记录的数据中,空闲内存(free)已经低于了内存最低水位线(low)。
[六 9月 11 12:24:42 2021] test invoked oom-killer: gfp_mask=0x62****(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), nodemask=(null), order=0,
[六 9月 11 12:24:42 2021] Task in /user.slice killed as a result of limit of host
[六 9月 11 12:24:42 2021] Node 0 DMA32 free:155160kB min:152412kB low:190512kB high:228612kB
[六 9月 11 12:24:42 2021] Node 0 Normal free:46592kB min:46712kB low:58388kB high:70064kB
原因:由于实例的空闲内存低于内存最低水位线,无法通过内存回收机制解决内存不足的问题,因此触发了OOM Killer。
内存节点(Node)的内存不足 如下日志记录的出现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
原因:在NUMA存储模式下,操作系统可能存在多个内存节点(可运行cat /proc/buddyinfo命令查看相关资源信息)。如果通过cpuset.mems参数指定cgroup只能使用特定内存节点的内存,则可能导致实例在具备充足的空闲内存的情况下,仍出现OOM Killer的情况。
内存碎片化时伙伴系统内存不足 如下日志记录的出现OOM Killer场景示例中,部分日志记录分析说明:
  • 操作系统在内存分配的order=3阶段出现了OOM Killer。
  • 内存节点Node 0的空闲内存(free)仍高于内存最低水位线(low)。
  • 内存节点Node 0对应的伙伴系统内存为0(0*32kB (M))。
[六 9月 11 15:22:46 2021] insmod invoked oom-killer: gfp_mask=0x60****(GFP_KERNEL), nodemask=(null), order=3, oom_score_adj=0
[六 9月 11 15:22:46 2021] insmod cpuset=/ mems_allowed=0
[六 9月 11 15:22:46 2021] Task in /user.slice killed as a result of limit of host
[六 9月 11 15:22:46 2021] Node 0 Normal free:23500kB min:15892kB low:19864kB high:23836kB active_anon:308kB inactive_anon:194492kB active_file:384kB inactive_file:420kB unevi    ctable:0kB writepending:464kB present:917504kB managed:852784kB mlocked:0kB kernel_stack:2928kB pagetables:9188kB bounce:0kB
[六 9月 11 15:22:46 2021] Node 0 Normal: 1325*4kB (UME) 966*8kB (UME) 675*16kB (UME) 0*32kB (M) 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB =
原因:操作系统的内存在进行内存分配的过程中,如果伙伴系统的内存不足,则系统会通过OOM Killer释放内存,并将内存提供至伙伴系统。

解决方案

阿里云提供了以下解决方案,您可以结合实际情况,排查并解决问题:

方案序号 方案说明
方案一

建议您自行评估实例内当前占用内存的进程情况,及时清理不需要的进程,以释放内存。如果您的业务所需的内存较大,当前实例规格不满足您对内存的需求,可以升配实例以提升实例的内存容量。更多信息,请参见升降配方式概述。在升配实例后,您还需要根据内存实际的提升情况,手动调整cgroup的内存上限。

调整cgroup内存上限的命令说明如下:
echo value > /sys/fs/cgroup/memory/test/memory.limit_in_bytes
其中,value为您为cgroup设置的内存上限。
方案二 检查实例内是否存在内存泄漏的情况。重点检查项:
  • 查看slab_unreclaimable内存使用情况。
    cat /proc/meminfo | grep "SUnreclaim"
    slab_unreclaimable内存为系统不可回收的内存,当占用总内存的10%以上时,表示系统可能存在slab内存泄漏。如果存在内存泄漏问题,您可以手动排查,具体操作,请参见如何排查Linux slab_unreclaimable内存占用高的原因?。如果问题始终未解决,请提交工单
  • 查看systemd内存使用情况。
    cat /proc/1/status | grep "RssAnon"
    内核发生OOM Killer时,会跳过系统的1号进程。此时您查看systemd内存使用情况时,一般不会超过200 MB。如果出现异常,您可以尝试自行更新systemd工具的版本。
  • 查看透明大页THP的性能。

    开启THP会出现内存膨胀(memory bloating),从而导致OOM Killer的出现。您可以对THP进行调优。具体操作,请参见Alibaba Cloud Linux 2系统中与透明大页THP相关的性能调优方法

方案三 内存节点(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

方案四 内存碎片化时导致的OOM Killer,建议您定期在业务空闲时间段,进行内存整理。开启内存整理功能的命令为:
echo 1 > /proc/sys/vm/compact_memory