OOM原理分析

本文详细解析了Linux内核中OOM(Out of Memory)的原理,包括其发生条件、处理机制以及配置策略。重点分析了内核中处理OOM事件的关键函数和流程,如__out_of_memory()、select_bad_process()与oom_kill_process(),并讨论了如何通过配置参数来优化内存管理,避免OOM情况的发生。

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

OOM原理分析

OOM全称是Out Of Memory,指的是kernel因分配不出内存而报的错误,同时会触发kernel调用OOM killer杀进程来解除这种状况。

OOM发生的条件一般有两个:

1. VM里面分配不出更多的page(注意linux kernel是延迟分配page策略,及用到的时候才alloc;所以malloc + memset才有效)。
2. 用户地址空间不足,这种情况在32bit机器上及user space超过了3GB,在64bit机器上不太可能发生。

下面通过分析linux kernel中oom_kill.c​代码来了解一下OOM的机制。OOM在kernel中对应的函数有两个:out_of_memory()和pagefault_out_of_memory(),最终调用的都是__out_of_memory()。 

__out_of_memory()做两件事情:
1. 调用select_bad_process选择一个要kill的进程;
2. 调用oom_kill_process杀死select出来的进程。

select_bad_process函数扫描整个进程列表:
1) 跳过kernel thread、没有占用mem的进程、INIT进程、以及被设置为OOM_DISABLE的进程;可以通过设置进程的 /proc/<pid>/oom_adj ​来调整oom_adj的值,oom_adj范围是[-17, 15],值越大越容易被oom kill掉,设为OOM_DISABLE(-17)的进程不会被oom。

2) 对其它的进程调用badness()函数来计算相应的score,score最高的将被选中。badness()函数计算score (points)的因子有下面几个:

a) score起始为该进程占用的total_vm;
points = mm->total_vm;

b) 如果该进程有子进程,子进程独自占用的total_vm/2加到本进程score;
points += child->mm->total_vm/2 + 1;

c) score和进程的cpu_time以及run_time成反比;
points /= int_sqrt(cpu_time);
points /= int_sqrt(int_sqrt(run_time));

d) nice大于0的进程,score翻倍;
if (task_nice(p) > 0) points *= 2;

e) 对设置了超级权限的进程和直接磁盘交互的进程降低score;
if (CAP_SYS_ADMIN | CAP_SYS_RESOURCE | CAP_SYS_RAWIO) points /= 4;

f) 如果和current进程在内存上没有交集的进程降低score;
if (!has_intersects_mems_allowed(p)) points /= 8;

g) 最后是根据该进程的oom_adj计算最终的score;
points <<= abs(oom_adj);

oom_kill_process函数的功能很简单,就一句话:

force_sig(SIGKILL, p);

可以看到发的是SIGKILL信号,其实就是执行kill -9 pid,因为SIGKILL是不能被捕获的。

可以通过下面两个参数来配置OOM策略:
/proc/sys/vm/overcommit_memory
/proc/sys/vm/overcommit_ratio

overcommit_memory取值为[0-2]:
0:表示按启发模式进行overcommit(可以提交超过物理内存大小的alloc page申请),也是默认的设置;
1:表示总是允许overcommit,这种模式最容易触发oom;
2:表示不能overcommit。这种模式下,最大的User Space限制在:SS + RAM*(r/100),SS是swap大小,r就是overcommit_ratio设置的值,范围为:[0-100]。

有一种mem_notify的机制在内存不足时可以给应用进程发信号,让应用进程去释放内存,如果不能释放再调用oom killer,但在linux 2.6.28以后的版本都不能用了,所以避免OOM还是做好应用的内存管理以及监控。

 参考资料:

        1.   http://lxr.linux.no/linux+v2.6.32.60/mm/oom_kill.c

        2.  http://lwn.net/Articles/267013/

        3.  http://www.kernel.org/doc/man-pages/online/pages/man5/proc.5.html

<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、付费专栏及课程。

余额充值