oom原理分析
来源:互联网 发布:js如何显示表单内容 编辑:程序博客网 时间:2024/06/08 11:24
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机器上不太可能发生。
下面通过分析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还是做好应用的内存管理以及监控。
Linux 内核 有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了 防止内存耗尽而内核会把该进程杀掉。典型的情况是:某天一台机器突然ssh远程登录不了,但能ping通,说明不是网络的故障,原因是sshd进程被 OOM killer杀掉了(多次遇到这样的假死状况)。重启机器后查看系统日志/var/log/messages会发现 Out of Memory: Kill process 1865(sshd)类似的错误信息。
防止重要的系统进程触发(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
点击(此处)折叠或打开
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机制
点击(此处)折叠或打开
vm.panic_on_oom = 1 //1表示关闭,默认为0表示开启OOM
# sysctl -p
为了验证OOM机制的效果,我们不妨做个测试。
首先看看我系统现有内存大小,没错96G多,物理上还要比查看的值大一些。
再看看目前进程最大的有哪些,top查看,我目前只跑了两个java程序的进程,分别4.6G,再往后redis进程吃了21m,iscsi服务占了32m,gdm占了25m,其它的进程都是几M而已。
现在我自己用C写一个叫bigmem程序,我指定该程序分配内存85G
点击(此处)折叠或打开
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define PAGE_SZ (1<<12)
-
- int main() {
- int i;
- int gb = 85; //以GB为单位分配内存大小
-
- for (i = 0; i < ((unsigned long)gb<<30)/PAGE_SZ ; ++i) {
- void *m = malloc(PAGE_SZ);
- if (!m)
- break;
- memset(m, 0, 1);
- }
- printf("allocated %lu MB\n", ((unsigned long)i*PAGE_SZ)>>20);
- getchar();
- return 0;
- }
继续观察,当bigmem稳定保持在85G一会后,内核会自动将其进程kill掉,增长的过程中没有被杀,如果不希望被杀可以执行
点击(此处)折叠或打开
pgrep -f "bigmem" | while read PID; do echo -17 > /proc/$PID/oom_adj;done
执行以上命令前后,明显会对比出效果,就可以体会到内核OOM机制的实际作用了。
如果你觉得写C代码麻烦,我告诉大家另外一个最简单的测试触发OOM的方法,可以把某个进程的oom_adj设置到15(最大值),最容易触发。然后执行以下命令:
点击(此处)折叠或打开
- echo f > /proc/sysrq-trigger // 'f' - Will call oom_kill to kill a memory hog process.
需要注意的是这个测试,只是模拟OOM,不会真正杀掉进程
点击(此处)折叠或打开
- ps -ef | grep mysqld | grep -v grep
注意:
1.Kernel-2.6.26之前版本的oomkiller算法不够精确,RHEL 6.x版本的2.6.32可以解决这个问题。
2.子进程会继承父进程的oom_adj。
3.OOM不适合于解决内存泄漏(Memory leak)的问题。
4.有时free查看还有充足的内存,但还是会触发OOM,是因为该进程可能占用了特殊的内存地址空间。
原文地址:Linux内核OOM机制的详细分析 作者:linuxnerd
本文摘自:http://blog.chinaunix.net/uid-25424552-id-3944805.html
http://lxr.linux.no/linux+v2.6.32.60/mm/oom_kill.c
http://lwn.net/Articles/267013/
http://www.kernel.org/doc/man-pages/online/pages/man5/proc.5.html
文章来源:http://qing.blog.sina.com.cn/1745498822/680a32c633002y78.html
- OOM原理分析
- oom原理分析
- OOM分析
- ThreadLocal出现OOM内存溢出的场景和原理分析
- Android—OOM原理
- Java OOM分析
- oom-kill分析
- oom-kill分析
- OOM(out_of_memory) killer分析
- OOM(out_of_memory) killer分析
- OOM killer分析
- OOM(out_of_memory) killer分析
- Android OOM分析总结
- android oom分析
- OOM(out_of_memory) killer分析
- android oom 分析
- android OOM异常分析
- 关于OOM问题分析
- springmvc http content-type
- codeforces.com/contest/839/
- 微服务开发的入门级框架Spring Boot详解(二)
- 4.3广义表
- Xilinx reVISION开搞!【reVISION】
- oom原理分析
- D
- 返回json数据中属性为null不参与序列化
- 本周计划
- 电话拨号器
- HDU6109-数据分割
- hibernate 报 LazyInitializationException
- Linux启动/停止/重启防火墙
- 最佳完美匹配性质1poj3565-边上的性质