• Linux 下的 OOM Killer理解Out of memory: Kill process


    Tomcat服务进程无故被杀掉。
    linux上tomcat服务器突然挂掉了,查看catalina.out没有发现什么错误信息。
    查看/var/log/messages文件发现是因为内存不足系统杀死的
    kernel: Out of memory: Kill process 15983 (java) score 149 or sacrifice child

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

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

    问题现象

    Linux操作系统在实例全局内存的内存不足时,会先触发内存回收机制释放内存,并将这部分被释放的内存分配给其他进程。如果内存回收机制不能处理系统内存不足的情况,则系统会触发OOM Killer强制释放进程占用的内存。触发OOM Killer的部分日志信息示例如下:

    1. 565 [六 911 12:24:42 2021] test invoked oom-killer: gfp_mask=0x62****(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), nodemask=(null), order=0, oom_score_adj=0
    2. 566 [六 911 12:24:42 2021] test cpuset=/ mems_allowed=0
    3. 567 [六 911 12:24:42 2021] CPU: 1 PID: 29748 Comm: test Kdump: loaded Not tainted 4.19.91-24.1.al7.x86_64 #1
    4. 568 [六 911 12:24:42 2021] Hardware name: Alibaba Cloud Alibaba Cloud ECS, BIOS e62**** 04/01/2014

    可能原因

    系统出现OOM Killer表示内存不足,内存不足可以分为实例全局内存不足和实例内cgroup的内存不足。这里只贴出实例全局内存不足:原文链接:出现OOM Killer的原因与解决方案

    1. [六 9月 11 15:22:46 2021] insmod invoked oom-killer: gfp_mask=0x60****(GFP_KERNEL), nodemask=(null), order=3, oom_score_adj=0
    2. [六 9月 11 15:22:46 2021] insmod cpuset=/ mems_allowed=0
    3. [六 9月 11 15:22:46 2021] Task in /user.slice killed as a result of limit of host
    4. [六 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
    5. [六 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场景示例中,部分日志记录分析说明:

    • 操作系统在内存分配的order=3阶段出现了OOM Killer。
    • 内存节点Node 0的空闲内存(free)仍高于内存最低水位线(low
      free:23500kB   low:19864kB
    • 内存节点Node 0对应的伙伴系统内存为0(0*32kB (M))。

     原因:操作系统的内存在进行内存分配的过程中,如果伙伴系统的内存不足,则系统会通过OOM Killer释放内存,并将内存提供至伙伴系统。

    解决方案

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

    方案序号方案说明
    方案一

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

    调整cgroup内存上限的命令说明如下:
    echo value > /sys/fs/cgroup/memory/test/memory.limit_in_bytes
    其中,value为您为cgroup设置的内存上限。
    方案四内存碎片化时导致的OOM Killer,建议您定期在业务空闲时间段,进行内存整理。开启内存整理功能的命令为:
    echo 1 > /proc/sys/vm/compact_memory

    Linux 内核根据应用程序的要求分配内存,通常来说应用程序分配了内存但是并没有实际全部使用,为了提高性能,这部分没用的内存可以留作它用,这部分内存是属于每个进程的,内核直接回收利用的话比较麻烦,所以内核采用一种过度分配内存(over-commit memory)的办法来间接利用这部分 “空闲” 的内存,提高整体内存的使用效率。一般来说这样做没有问题,但当大多数应用程序都消耗完自己的内存的时候麻烦就来了,因为这些应用程序的内存需求加起来超出了物理内存(包括 swap)的容量,内核(OOM killer)必须杀掉一些进程才能腾出空间保障系统正常运行。用银行的例子来讲可能更容易懂一些,部分人取钱的时候银行不怕,银行有足够的存款应付,当全国人民(或者绝大多数)都取钱而且每个人都想把自己钱取完的时候银行的麻烦就来了,银行实际上是没有这么多钱给大家取的。

    内核检测到系统内存不足、挑选并杀掉某个进程的过程可以参考内核源代码 linux/mm/oom_kill.c,当系统内存不足的时候,out_of_memory() 被触发,然后调用 select_bad_process() 选择一个 “bad” 进程杀掉,如何判断和选择一个 “bad” 进程呢,总不能随机选吧?挑选的过程由 oom_badness() 决定,挑选的算法和想法都很简单很朴实:最 bad 的那个进程就是那个最占用内存的进程。

    理解了这个算法我们就理解了为啥 MySQL 躺着也能中枪了,因为它的体积总是最大(一般来说它在系统上占用内存最多),所以如果 Out of Memeory (OOM) 的话总是不幸第一个被 kill 掉。解决这个问题最简单的办法就是增加内存,或者想办法优化 MySQL 使其占用更少的内存,除了优化 MySQL 外还可以优化系统(优化 Debian 5优化 CentOS 5.x),让系统尽可能使用少的内存以便应用程序(如 MySQL) 能使用更多的内存,还有一个临时的办法就是调整内核参数,让 MySQL 进程不容易被 OOM killer 发现。

    从上面的 oom_kill.c 代码里可以看到 oom_badness() 给每个进程打分,根据 points 的高低来决定杀哪个进程,这个 points 可以根据 adj 调节,root 权限的进程通常被认为很重要,不应该被轻易杀掉,所以打分的时候可以得到 3% 的优惠(adj -= 30; 分数越低越不容易被杀掉)。我们可以在用户空间通过操作每个进程的 oom_adj 内核参数来决定哪些进程不这么容易被 OOM killer 选中杀掉。比如,如果不想 Mysql 进程被轻易杀掉的话可以找到 Mysql 运行的进程号后,调整 oom_score_adj 为 -15(注意 points 越小越不容易被杀):

    1. # ps aux | grep mysqld
    2. mysql 2196 1.6 2.1 623800 44876 ? Ssl 09:42 0:00 /usr/sbin/mysqld
    3. # cat /proc/2196/oom_score_adj
    4. 0
    5. # echo -15 > /proc/2196/oom_score_adj

    Tomcat进程被杀掉也是基于此原理:

    总结:

    应用程序申请分配内存,并不会立马全部使用,只要这些应用程序的实际使用内存加起来 没有超出了物理内存(包括 swap)的容量,就相安无事,但是应用程序使用过程中会增加,直到增加到申请的最大内存为止。这个过程中就可能会导致实际使用内存加起来超出了物理内存(包括 swap)的容量就被内核OOM killer,这个过程我们tomcat并没有到达自己申请的最大内存,但是就是因为自己评分低,也就被无故被杀掉。

    解决办法

    1、增加Linux内存

    2、减小jvm最大堆内存 -Xmx=16G

    3、增加 swap 交换区大小

        Linux 增加swap 分区大小

    4、调节tomcat的oom_score_adj参数,

    1. #查看java进程pid,默认为0
    2. cat /proc/进程pid/oom_score_adj
    3. 0
    4. #修改java进程的oom_score_adj,越小越不易被系统内核杀掉
    5. echo -15 > /proc/进程pid/oom_score_adj

    参考:
    出现OOM Killer的原因与解决方案

    Linux 下的 OOM Killer理解和配置_boonya的博客-CSDN博客

  • 相关阅读:
    MCU软核 1. Altera FPGA上运行8051
    第五章 Docker 自定义镜像
    Redis+整合SpringDataRedis
    【Vue】作用域插槽
    技术分享| 融合调度中的广播功能设计
    Jest单元测试(一)
    GDB符号表概念及Linux获取符号表的方式
    Vue3动态显示时间
    CopyOnWriteArrayList源码分析
    端口占用,无法通过netstat找到进程,占用的端口又不能修改,该怎么办?
  • 原文地址:https://blog.csdn.net/u014644574/article/details/127403954