出现OOM Killer的原因及解决方案

Linux操作系统内存不足时,会先触发内存回收机制释放内存,并将这部分被释放的内存分配给其他进程。如果内存回收机制不能处理系统内存不足的情况,则系统会触发OOM Killer(Out of Memory Killer)强制释放进程占用的内存,达到给系统解压的目的。本文介绍Alibaba Cloud Linux操作系统出现OOM Killer的可能原因及解决方案。

问题现象

Alibaba Cloud Linux操作系统出现OOM Killer的部分日志信息示例如下,表示test进程引发了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),因此触发了OOM Killer。

父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。

系统全局内存不足

如下日志记录的出现OOM Killer场景示例中,limit of host表示实例的全局内存出现了不足。在日志记录的数据中,内存节点Node 0的空闲内存(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释放内存,并将内存提供至伙伴系统。

说明

在Linux操作系统中,伙伴系统(Buddy System)是内核内存管理的一种机制,它能够减轻内存碎片问题,并且高效地分配和释放不同大小的内存块。

解决方案

请您结合实际出现的OOM Killer场景,按照以下步骤排查并解决问题:

子cgroup或父cgroup内存不足

建议您自行评估实例内当前占用内存的进程情况,及时清理不需要的进程,以释放内存。如果您的业务所需的内存较大,当前实例规格不满足您对内存的需求,可以升配实例以提升实例的内存容量。

  1. 升配实例。

    更多信息,请参见升降配方式概述

  2. 根据内存实际的提升情况,手动调整cgroup的内存上限。

    sudo bash -c 'echo <value> > /sys/fs/cgroup/memory/<cgroup_name>/memory.limit_in_bytes'

    其中,<value>为您为cgroup设置的内存上限、<cgroup_name>为您实际的cgroup名称,请根据实际情况替换。

系统全局内存不足

如果出现系统全局内存不足,请您重点排查以下几项:

  • 查看slab_unreclaimable内存使用情况。

    cat /proc/meminfo | grep "SUnreclaim"

    slab_unreclaimable内存为系统不可回收的内存,当占用总内存的10%以上时,表示系统可能存在slab内存泄露。如果存在内存泄露问题,您可以手动排查并解决,具体操作,请参见如何排查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系统中与透明大页THP相关的性能调优方法

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

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

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

    cat /proc/buddyinfo
  2. 配置cpuset.mems接口。

    sudo bash -c 'echo <value> > /sys/fs/cgroup/cpuset/<cgroup_name>/cpuset.mems'

    其中,<value>为对应的内存节点号、<cgroup_name>为您实际的cgroup名称,请根据实际情况替换。

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

内存碎片化时伙伴系统内存不足

内存碎片化时导致的OOM Killer,建议您定期在业务空闲时间段,进行内存整理。开启内存整理功能的命令为:

sudo bash -c 'echo 1 > /proc/sys/vm/compact_memory'