目录
简述
Linux内核根据应用程序的要求分配内存,通常来说应用程序分配了内存但是并没有实际全部使用,为了提高性能,这部分没用的内存可以留作它用,这部分内存是属于每个进程的,内核直接回收利用的话比较麻烦,所以内核采用一种过度分配内存(over-commit memory)的办法来间接利用这部分“空闲”的内存,提高整体内存的使用效率。一般来说这样做没有问题,但当大多数应用程序都消耗完自己的内存的时候麻烦就来了,因为这些应用程序的内存需求加起来超出了物理内存(包括swap)的容量,内核(OOM killer)必须杀掉一些进程才能腾出空间保障系统正常运行。
Linux内核有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了防止内存耗尽内核会把该进程杀掉。
实现简述
内核检测到系统内存不足、挑选并杀掉某个进程的过程可以参考内核源代码 linux/mm/oom_kill.c,当系统内存不足的时候,out_of_memory()被触发,然后调用 select_bad_process() 选择一个“bad”进程杀掉,判断和选择一个“bad”进程的过程由 oom_badness()决定,最 bad 的那个进程就是那个最占用内存的进程。
oom_badness() 给每个进程打分,根据 points 的高低来决定杀哪个进程,这个 points 可以根据 adj 调节,root 权限的进程通常被认为很重要,不应该被轻易杀掉,所以打分的时候可以得到 3% 的优惠(分数越低越不容易被杀掉)。badness score的计算会用到进程的内存大小,CPU时间(user time + system time) 运行时间,以及oom_adj值。进程消耗的内存越多,得分就越高;进程运行的时间越长,得分就越低。这也解释了,为什么新fork出来的进程容易被杀死,因为它的运行时间短,得分高
oom killer选择进程的策略大致如下:
- 它必须拥有大量的页框
- 杀掉这个进程只会损失少量的工作
- 它的静态优先级必须低(可以通过nice来给不重要的进程设置低的优先级)
- 它不能够拥有root权限
- 它不能直接访问硬件
- 它不能够是0号进程(swapper),1号进程(init),以及内核线程
如何发现
系统日志关键字
grep oom /var/log/syslog
eat_memory invoked oom-killer
如何禁用OOM-killer
系统级
通过禁用overcommit方法
参数 /proc/sys/vm/overcommit_memory 可以控制进程对内存过量使用的应对策略
如果禁用overcommit,那么不会出现oom killer,但是系统的内存利用效率会降低,不建议在生产环境使用。
- 当overcommit_memory=0 允许进程轻微过量使用内存,但对于大量过载请求则不允许(默认)
- 当overcommit_memory=1 永远允许进程overcommit
- 当overcommit_memory=2 永远禁止overcommit
通过重启kernel panic方法
A.
sysctl -w vm.panic_on_oom=1
sysctl -w kernel.panic=10
B.
echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=10" >> /etc/sysctl.conf
进程级
Linux下每个进程都有个OOM权重,在/proc/<pid>/oom_adj里面,取值是-17到+15,取值越高,越容易被干掉。
因此,将-17写入该文件,进程不会被OOM killer。
echo -17 >/proc/2001/oom_adj
附录1:cgroup中的OOM killer
可参考:https://segmentfault.com/a/1190000008125359
附录2:查看overcommit状态
[root@oracletest ~]# cat /proc/meminfo |grep Commit
CommitLimit: 23750060 kB
Committed_AS: 289016 kB
参考:
https://www.cnblogs.com/GoodGoodWorkDayDayUp/p/3473348.html
https://blog.csdn.net/hunanchenxingyu/article/details/26271293
https://lwn.net/Articles/317814/
https://www.cnblogs.com/jjmcao/p/9450383.html