当前位置: 首页 > news >正文

Linux内核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

为了避免重启失效,可以写入/etc/rc.d/rc.local

点击(此处)折叠或打开

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机制

 

点击(此处)折叠或打开

# sysctl -w vm.panic_on_oom=1
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

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #define PAGE_SZ (1<<12)
  6.  
  7. int main() {
  8.     int i;
  9.     int gb = 85; //以GB为单位分配内存大小
  10.  
  11.     for (i = 0; i < ((unsigned long)gb<<30)/PAGE_SZ ; ++i) {
  12.         void *m = malloc(PAGE_SZ);
  13.         if (!m)
  14.             break;
  15.         memset(m, 0, 1);
  16.     }
  17.     printf("allocated %lu MB\n", ((unsigned long)i*PAGE_SZ)>>20);
  18.     getchar();
  19.     return 0;
  20. }
呵呵,效果明显,然后执行后再用top查看,排在第一位的是我的bigmem,RES是物理内存,已经吃满了85G。

 

 

继续观察,当bigmem稳定保持在85G一会后,内核会自动将其进程kill掉,增长的过程中没有被杀,如果不希望被杀可以执行

点击(此处)折叠或打开

pgrep -f "bigmem" | while read PID; do echo -17 > /proc/$PID/oom_adj;done

执行以上命令前后,明显会对比出效果,就可以体会到内核OOM机制的实际作用了。

 

如果你觉得写C代码麻烦,我告诉大家另外一个最简单的测试触发OOM的方法,可以把某个进程的oom_adj设置到15(最大值),最容易触发。然后执行以下命令:

点击(此处)折叠或打开

  1. echo f > /proc/sysrq-trigger // 'f' - Will call oom_kill to kill a memory hog process.
以下我来触发mysqld的OOM看看:

需要注意的是这个测试,只是模拟OOM,不会真正杀掉进程

 

点击(此处)折叠或打开

  1. ps -ef | grep mysqld | grep -v grep
查看mysql进程,发现依然存在

 

 

注意:

1.Kernel-2.6.26之前版本的oomkiller算法不够精确,RHEL 6.x版本的2.6.32可以解决这个问题。

2.子进程会继承父进程的oom_adj。

3.OOM不适合于解决内存泄漏(Memory leak)的问题。

4.有时free查看还有充足的内存,但还是会触发OOM,是因为该进程可能占用了特殊的内存地址空间。

转载于:https://www.cnblogs.com/Ph-one/p/4815808.html

相关文章:

  • 友好博客集
  • android系统平台显示驱动开发简要:LCD基本原理篇『一』
  • android系统平台显示驱动开发简要:LCD常用接口篇『二』
  • cadence allegro PCB中怎么使查找元件时屏幕不移动
  • FrameBuffer
  • android系统平台显示驱动开发简要:Samsung LCD接口篇『三』
  • android系统平台显示驱动开发简要:LCD驱动调试篇『四』
  • 驱动之路-platform简例按键驱动☆☆☆
  • Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析[转]
  • android 电容屏(一):电容屏基本原理篇
  • android 电容屏(二):驱动调试之基本概念篇
  • android 电容屏(三):驱动调试之驱动程序分析篇
  • 在Ubuntu 12.04安装和设置SSH服务
  • 在Ubuntu 12.04安装和设置Samba实现网上邻居共享
  • 使用SecureCRT连接ubuntu
  • 10个确保微服务与容器安全的最佳实践
  • Linux中的硬链接与软链接
  • python docx文档转html页面
  • ViewService——一种保证客户端与服务端同步的方法
  • 给github项目添加CI badge
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 免费小说阅读小程序
  • 我这样减少了26.5M Java内存!
  • Hibernate主键生成策略及选择
  • ​Spring Boot 分片上传文件
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • $ git push -u origin master 推送到远程库出错
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (二)c52学习之旅-简单了解单片机
  • (九)信息融合方式简介
  • (理论篇)httpmoudle和httphandler一览
  • (论文阅读40-45)图像描述1
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • .Family_物联网
  • .NET 5种线程安全集合
  • .net framework profiles /.net framework 配置
  • .Net 路由处理厉害了
  • .NET 依赖注入和配置系统
  • @Autowired注解的实现原理
  • [ 2222 ]http://e.eqxiu.com/s/wJMf15Ku
  • [Angular 基础] - 表单:响应式表单
  • [BJDCTF 2020]easy_md5
  • [C#]winform制作圆形进度条好用的圆环圆形进度条控件和使用方法
  • [Go WebSocket] 多房间的聊天室(五)用多个小锁代替大锁,提高效率
  • [HNOI2008]Cards
  • [idea]关于idea开发乱码的配置
  • [Linux内存管理-分页机制]—把一个虚拟地址转换为物理地址
  • [linux运维] 利用zabbix监控linux高危命令并发送告警(基于Zabbix 6)
  • [Python] Ubuntu12.04LTS
  • [python]基于opencv实现的车道线检测
  • [Python学习]总结一下Cygwin安装与进阶学习列表
  • [RoarCTF 2019]PHPShe
  • [SOA介绍]什么是SOA?