(3条消息) Linux内核OOM机制的详细分析和防止进程被OOM杀死的方法

转载自:http://blog.chinaunix.net/uid-29242873-id-3942763.htmlLinux 内核有个机制叫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=1vm .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点击(此处)折叠或打开#include <stdio.h>#include <stdlib.h>#include <string.h>#define PAGE_SZ (1<<12)int main() {int i;int gb = 85; //以GB为单位分配内存大小for (i = 0; i < ((unsigned long)gb<<30)/PAGE_SZ ; ++i) {void *m = malloc(PAGE_SZ);if (!m)break;memset(m, 0, 1);}printf("allocated %lu MB\n", ((unsigned long)i*PAGE_SZ)>>20);getchar();return 0;}呵呵,效果明显,然后执行后再用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(最大值),最容易触发。然后执行以下命令:点击(此处)折叠或打开echo f > /proc/sysrq-trigger // 'f' - Will call oom_kill to kill a memory hog process.以下我来触发mysqld的OOM看看:

需要注意的是这个测试,只是模拟OOM,不会真正杀掉进程点击(此处)折叠或打开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,是因为该进程可能占用了特殊的内存地址空间。

(0)

相关推荐

  • 直击面试现场——Linux运维面试——犀利24问

    系统管理员这个职业它需要一个了解系统工作原理的人,这样的人才才能保证数据的安全和服务器的平稳运行. 但是,小伙伴们可能会问:「难道系统管理员就只能做这些吗?」答案是否定的! 让我先给大家介绍一下典型的 ...

  • Linux服务器Java进程突然消失排查办法

    出处:JAVA进程突然消失的原因? 问题描述 在实际生产环境下,如果我们遇见Java进程突然消失,该如何去排查问题? 思路 可能有几种原因: ①.Java应用程序的问题:发生OOM导致进程Crash ...

  • (1条消息) linux内核的内存分配函数

    作用 函数 devm_kzalloc() 和kzalloc()一样都是内核内存分配函数,但是devm_kzalloc()是跟设备(device)有关的, 当设备(device)被detached或者驱 ...

  • (2条消息) Linux so剖析

    Linux so剖析 此处so指Shared Object,即动态链接库,本文将从so文件格式开始讲述,在了解完so文件格式的必要知识后,接下来最简概述so的生成,即编译器的静态链接,然后便是so的加 ...

  • (7条消息) Linux C/C++ 获取当前工作目录

    在windows系统下,getcwd()函数是在#include <direct.h>: Linux系统,则是在#include <unistd.h>. 1.getcwd() ...

  • (7条消息) linux命令基本使用

    练习文件查看及检索操作. 查看/etc/filesystems文件,确认当前系统支持的文件系统类型. [root@centos06 ~]# cat /etc/filesystems xfs ext4 ...

  • (7条消息) linux send与recv函数详解

    转载地址: http://blog.csdn.net/sjin_1314/article/details/9565743 [csharp]  view plain  copy   print ? 1  ...

  • (7条消息) Linux下TCP/IP编程

    本文参考自徐晓鑫<后台开发>,重点复习总结TCP通信流程,读者也可以参考: http://blog.csdn.net/wqc_csdn/article/details/51513543,谢 ...

  • (4条消息) Linux 基础操作、常用shell命令、vi常用命令、man帮助手册

    一.简述 记录简单的Linux 基础操作.常用shell命令.vi编辑器常用命令.man帮助手册的使用. 二.Linux 基础操作 1.按 Ctrl+Alt+t 快捷键或者双击桌面的"Ter ...

  • (1条消息) Linux下使用openssl生成证书

    利用OpenSSL生成库和命令程序,在生成的命令程序中包括对加/解密算法的测试,openssl程序,ca程序.利用openssl,ca可生成用于C/S模式的证书文件以及CA文件. 证书文件的生成步骤: ...

  • (9条消息) linux下opencv4.2编译cuda的那些坑

    目录 1.编译cmake 2.配置 3. 编译 4. opencv4.2使用中的问题 1. c++11标准的支持 2. cuda支持 前言:opencv4.2版本19年12月发布,其最重要的改变是增加 ...