最新消息:

OOM原理分析

分析 admin 2964浏览 0评论

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还是做好应用的内存管理以及监控。

 

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

 

转载请注明:爱开源 » OOM原理分析

您必须 登录 才能发表评论!