消失的Java进程-Linux OOM Killer

当Java进程在Linux系统上无故消失,可能是遭遇了OOM Killer。通过检查服务器日志和oom_score,确认Java进程由于内存消耗过高被系统自动终止。解决方案包括在Docker启动命令中限制内存分配,以及调整进程的oom_adj值以避免被OOM Killer选中。可以通过设置oom_adj为-17来临时关闭特定进程的OOM机制,如sshd,并通过定时任务确保设置持久生效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一台虚拟机上执行docker java应用,每隔一段时间就会出现java进程消失、而且没有任何jvm error log的情况。

略一寻思,应该是遇到网上常说的Linux OOM的情况:虚拟机10G,docker默认分配内存未做限制。

原因定位

去服务器上执行:dmesg | grep java,果然有数据

并且查看文件: /var/log/messages 定位关键字:oom-killer,

看到相关信息:java pid信息,

memory: usage 2047696kB, limit 2047696kB, failcnt 23543
memory+swap: usage 2047696kB, limit 9007199254740991kB, failcnt 0
......
Free swap  = 0kB
Total swap = 0kB
......
Memory cgroup out of memory: Kill process 18286 (java) score 933 or sacrifice child

最终java进程被Linux OOM弄死了:因为oom的score太高了:933。启动的时候score是225,进程的oom_score 分数越高,越容易被 OOM Killer 杀掉。使用如下脚本检测oom score:

# vi oomscore.sh
#!/bin/bash
for proc in $(find /proc -maxdepth 1 -regex '/proc/[0-9]+'); do
    printf "%2d %5d %s\n" \
        "$(cat $proc/oom_score)" \
        "$(basename $proc)" \
        "$(cat $proc/cmdline | tr '\0' ' ' | head -c 50)"
done 2>/dev/null | sort -nr | head -n 10
# chmod +x oomscore.sh

参考:http://www.vpsee.com/2013/10/how-to-configure-the-linux-oom-killer/

解决方案

在docker run命令中加入 -m 4000m,参考:https://jiajially.gitbooks.io/dockerguide/content/chapter_fastlearn/docker_run/-m.html,这个时候默认swap是8000m。

网络上的方案:禁止OOM的方案

例如文章所写:http://coolnull.com/3577.html

防止重要的系统进程触发(OOM)机制而被杀死:可以设置参数/proc/PID/oom_adj为-17,可临时关闭linux内核的OOM机制。内核会通过特定的算法给每个进程计算一个分数来决定杀哪个进程,每个进程的oom分数可以/proc/PID/oom_score中找到。我们运维过程中保护的一般是sshd和一些管理agent。

保护某个进程不被内核杀掉可以这样操作:

# echo -17 > /proc/$PID/oom_adj

如何防止sshd被杀,可以这样操作:

# pgrep -f "/usr/sbin/sshd" | while read PID;do echo -17 > /proc/$PID/oom_adj;done

可以在计划任务里加入这样一条定时任务,就更安全了:

#/etc/cron.d/oom_disable
*/1**** root pgrep -f "/usr/sbin/sshd" | while read PID;do echo -17 > /proc/$PID/oom_adj;done

为了避免重启失效,可以写入/etc/rc.d/rc.local

echo -17 > /proc/$(pidof sshd)/oom_adj

至于为什么用-17而不用其他数值(默认值为0),这个是由linux内核定义的,查看内核源码可知:
以linux-3.3.6版本的kernel源码为例,路径为linux-3.6.6/include/linux/oom.h,阅读内核源码可知oom_adj的可调值为15到-16,其中15最大-16最小,-17为禁止使用OOM。oom_score为2的n次方计算出来的,其中n就是进程的oom_adj值,所以oom_score的分数越高就越会被内核优先杀掉。

当然还可以通过修改内核参数禁止OOM机制

# sysctl -w vm.panic_on_oom=1
vm.panic_on_oom = 1 //1表示关闭,默认为0表示开启OOM

# sysctl -p
<think>嗯,用户想深入了解LinuxOOMkiller的分析工具和解决方案。从用户提问的措辞看,ta应该是遇到实际OOM问题了,需要具体的排查手段而非理论解释。用户引用的资料里包含三个站内引用:-引用1提到触发OOM的实验方法(Python内存耗尽代码)、基础原理-引用2强调内核参数配置和进程优先级调整-引用3详述了工作机制和内存管理背景需要整合这些信息,但重点要落在用户要的“工具”和“解决方案”上。注意到ta上次提问已了解过原理,这次明显是实操需求。用户可能正在经历生产环境OOM,情绪上比较急切。回复需要:①立即可用的诊断命令(如dmesg/syslog筛查)②缓解方案排序:快速止血方法(临时调整score_adj)和根治方案(内存分析)③给出风险提示(如oom_score_adj的副作用)特别要注意引用1末尾的Python测试代码很有用,可以改写成更安全的测试方案(带内存限制的测试脚本)。对于解决方案层次:1.短期:优先级调整+进程保护2.中期:应用内存优化3.长期:架构扩容内存分析工具要区分实时监控(htop)和事后分析(coredump),用户可能更需要前者。引用2提到的/proc参数调整要强调安全范围,避免随意修改oom_kill_allocating_task导致雪崩。</think> 基于Linux OOM Killer的分析工具及解决方案如下,结合系统监控、内核机制和调优策略分步说明: --- ### **一、分析工具(诊断OOM事件)** 1. **`dmesg`日志分析** - 核心工具:OOM Killer触发后会在系统日志中记录详细信息 ```bash dmesg -T | grep -i "killed process" # 或直接查看系统日志 grep -i "oom" /var/log/syslog ``` - 输出示例: ``` [Tue Jun 4 10:23:45 2024] Out of memory: Killed process 1234 (java) [Tue Jun 4 10:23:45 2024] oom-kill:constraint=CONSTRAINT_NONE [...] oom_score=987 ``` 2. **`/proc`文件系统** - **`/proc/<pid>/oom_score`**:进程当前OOM评分(越高越易被杀) - **`/proc/<pid>/oom_score_adj`**:用户可调的评分修正值(范围:-1000~1000) - **实时查看**: ```bash watch -n 1 "cat /proc/*/oom_score | sort -nr | head -n 5" ``` 3. **监控工具** - `htop`/`top`:实时内存占用排名 - `vmstat 1`:监控swap使用、内存回收压力 - `sar -r 1`:历史内存使用趋势(需安装`sysstat`) --- ### **二、解决方案(预防与调优)** #### **1. 优先级调整:保护关键进程** ```bash # 降低关键进程OOM Killer选中的概率(设为负值) echo -1000 > /proc/<pid>/oom_score_adj ``` - **永久生效**:在启动脚本中添加`echo -1000 > /proc/self/oom_score_adj` #### **2. 内核参数调优** | 参数路径 | 作用 | 推荐值 | |---|---|---| | `/proc/sys/vm/panic_on_oom` | 是否系统崩溃 | `0`(启用OOM Killer) | | `/proc/sys/vm/oom_kill_allocating_task` | 是否杀死申请者 | `0`(评估所有进程) | | `/proc/sys/vm/overcommit_memory` | 内存分配策略 | `2`(禁止过度分配)[^2] | | `/proc/sys/vm/swappiness` | Swap使用倾向 | `10`(避免频繁swap) | #### **3. 应用层优化** - **限制进程内存**: ```bash systemd服务配置:MemoryLimit=2G # cgroup限制 或使用 ulimit -v 2000000 # 虚拟内存上限 ``` - **内存泄漏检测**: - C/C++:`valgrind --leak-check=yes` - Java:`jmap -histo <pid>` + MAT分析堆转储 #### **4. 兜底策略** - **Kdump+Coredump**:崩溃时保存内存快照 ```bash # 启用coredump echo "/tmp/core-%e-%p" > /proc/sys/kernel/core_pattern ulimit -c unlimited ``` - **容器环境**:Kubernetes设置`resources.limits.memory` --- ### **三、特殊场景处理** 1. **OOM未触发但内存耗尽** - 检查`/proc/sys/vm/overcommit_memory=2`,并确保`/proc/sys/vm/overcommit_ratio`合理 - 确认未禁用swap:`free -m`查看swap分区状态 2. **频繁OOM但内存未满** - 可能原因:内核碎片化(`buddyinfo`查看) - 解决方案:启用透明大页(THP)或重启服务释放碎片[^3] --- ### **
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值