大家好,我是极客范的本期栏目编辑小友,现在为大家讲解linux内核oom机制分析问题。
Linux内核有一个机制叫做OOM killer(Out-Of-Memory killer),它监控那些占用过多内存的进程,尤其是那些瞬间消耗大量内存的进程,内核会为了防止内存耗尽而杀死进程。典型情况:有一天,一台机器突然无法通过ssh远程登录,但可以ping通,说明不是网络故障,因为ssh进程被OOM杀手杀死了(这样的假死是多次遇到的)。重新启动机器后查看系统日志/var/log/messages,会发现类似的错误信息如内存不足:kill process 1865 (sshd)。
防止重要的系统进程触发(oom)机制被扼杀:可以将参数/proc/PID/oom_adj设置为-17,暂时关闭linux内核的OOM机制。内核将通过特定的算法为每个进程计算一个分数,以决定杀死哪个进程。每个流程的oom分数可以在/proc/PID/oom_score中找到。在操作和维护过程中,我们一般会保护sshd和一些管理代理。
要保护进程不被内核杀死,您可以这样做:
echo-17 ”/proc/$ PID/oom _ adj
如何防止sshd被杀死,可以通过以下方式完成:
pgrep -f"/usr/sbin/sshd"|在读取PID时;do echo-17 ”/proc/$ PID/oom _ adj;完成的
将这样的计划任务添加到计划任务中更安全:
#/etc/cron.d/oom_disable
*/1****根pgrep -f"/usr/sbin/sshd"|在读取PID时;do echo-17 ”/proc/$ PID/oom _ adj;完成的
为了避免重启失败,可以写/etc /etc/rc.d/rc.local
echo-17 ”/proc/
至于为什么用-17代替其他值(默认值为0),这是linux内核定义的,从内核源代码可以看到:
以linux-3.3.6版本的内核源代码为例,路径为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机制也可以通过修改内核参数来禁止。
# sysctl -w vm .恐慌_on_oom=1
Vm .恐慌_on_oom=1 //1表示关闭,默认值为0表示打开oom。
# sysctl -p
为了验证OOM机制的效果,我们不妨做一个测试。
首先,看看我的系统现有的内存大小,超过96G,物理上比检查的值大。
看看目前最大的流程。从顶视图来看,我目前只运行了两个java程序,分别是4.6G。未来,redis进程ate 21m万,iscsi服务占3200万,gdm占2500万,其他进程只有几米。
现在我用C语言写了一个叫bigmem的程序,我指定这个程序分配85G内存。
#包括《stdio.h》
#包括《stdlib.h》
#包括《string.h》
#定义PAGE _ SZ(1)《12》
int main(){ 0
int I;
int gb=85//以GB为单位分配内存大小。
for(I=0;I 《(无符号长)GB》《30)/PAGE _ SZ;I){ 0
void * m=malloc(PAGE _ SZ);
if(!m)
打破;
memset(m,0,1);
}
printf("已分配%lu MB\n",((无符号长)I * PAGE _ SZ)】20);
getchar();
返回0;
}
效果明显,执行后再与高层核对。我的bigmem排名第一,RES是物理内存,已经吃过85G了。
继续观察,当bigmem在85G保持稳定一段时间后,内核会自动杀死它的进程,但在成长过程中并没有被杀死。如果你不想被杀死,你可以执行它。
阅读PID时,单击(此处)折叠或打开pgrep-f“big mem”|;do echo-17 ”/proc/$ PID/oom _ adj;完成的
执行上述命令前后,效果会有明显的对比,可以实现内核OOM机制的实际功能。
如果你觉得写C代码很麻烦,我会告诉你另一个最简单的测试和触发OOM的方法。您可以将某个进程的oom_adj设置为15(最大值),这是最容易触发的。然后执行以下命令:
echo f ”/proc/sysrq-trigger/“f”-将调用oom_kill来杀死内存占用进程。
让我触发mysqld的OOM看看:
需要注意的是,这个测试只是模拟OOM,并不会真正扼杀这个过程。
ps -ef | grep mysqld | grep -v grep
纵观mysql进程,它依然存在。
注意:
1.1之前的oomkiller算法。内核-2.6.26不够准确。RHEL 6.x的2.6.32可以解决这个问题。
2.子进程将继承父进程的oom_adj。
3.OOM不适合解决内存泄漏的问题。
4.有时候有足够的内存可以自由查看,但是OOM仍然会被触发,因为进程可能会占用一个特殊的内存地址空间。