OOM_killer是Linux自我保护的一种机制,当内存不足时不至于出现太严重问题,如果内存不足将唤醒oom_killer,选出/proc/<pid>/oom_score最大的并将之kill掉。
为了保护重要进程不被oom-killer掉,可以禁用OOM
echo -17 > /proc/<pid>/oom_adj # -17表示禁用OOM
禁用整个系统的OOM:
sysctl -w vm.panic_on_oom=1
sysctl -p
值得注意的是,有些时候 free -m时还有剩余内存,但还是会触发OOM-killer,可能是因为进程占用了特殊的内存地址。
可用top M查看内存占用最大进程,但也不是进程一超过就会触发oom_killer,参数/proc/sys/vm/overcommit_memory可以控制进程对内存过量使用的应对策略,当overcommit_memory=0 允许进程轻微过量使用内存,但对于大量过载请求则不允许,当overcommit_memory=1 永远允许进程overcommit,当overcommit_memory=2 永远禁止overcommit。
Linux中malloc返回非空指针,并不一定意味着指向的内存就是可用的,Linux下允许程序申请比系统可用内存更多的内存,这个特性叫Overcommit。这样做是出于优化系统考虑,因为不是所有的程序申请了内存就立刻使用的,当你使用的时候说不定系统已经回收了一些资源了。不幸的是,当你用到这个Overcommit给你的内存的时候,系统还没有资源的话,OOM killer就跳出来了。
Linux下有3种Overcommit的策略(参考内核文档:vm/overcommit-accounting),可以在/proc/sys/vm/overcommit_memory配置。取0,1和2三个值,默认是0。
0:启发式策略,比较严重的Overcommit将不能得逞,比如你突然申请了128TB的内存。而轻微的Overcommit将被允许。另外,root能Overcommit的值比普通用户要稍微多些。
1:永远允许Overcommit,这种策略适合那些不能承受内存分配失败的应用。
2:永远禁止Overcommit,在这个情况下,系统所能分配的内存不会超过swap+RAM*系数(/proc/sys/vm/overcmmit_ratio,默认50%,你可以调整),如果这么多资源已经用光,那么后面任何尝试申请内存的行为都会返回错误,这通常意味着此时没法运行任何新程序。
OOM_killer进程选择策略
Linux下这个选择策略也一直在不断的演化。作为用户,我们可以通过设置一些值来影响OOM killer做出决策。Linux下每个进程都有个OOM权重,在/proc/<pid>/oom_adj里面,取值是-17到+15,取值越高,越容易被干掉。
最终OOM killer是通过/proc/<pid>/oom_score这个值来决定哪个进程被干掉的。这个值是系统综合进程的内存消耗量、CPU时间(utime + stime)、存活时间(uptime - start time)和oom_adj计算出的,消耗内存越多分越高,存活时间越长分越低。总之,总的策略是:损失最少的工作,释放最大的内存同时不伤及无辜的用了很大内存的进程,并且杀掉的进程数尽量少。
另外,Linux在计算进程的内存消耗的时候,会将子进程所耗内存的一半同时算到父进程中。这样,那些子进程比较多的进程就要小心了。
参考文章:Taming the OOM killer和When Linux Runs Out of Memory。