oom_killer
Limited Memory
今天在虚拟机里面用Word处理文档的时候,突然硬盘灯一阵狂闪,然后虚拟机就一起消失了。
这种事情屡见不鲜,很明显是Linux内核把占用最多内存的程序(这次是VirtualBox)终止掉了,而硬盘灯为什么会狂闪呢?这是因为在内存 用光之前,Linux的pdflush会把dirty pages写回磁盘上腾出内存给其他程序用。这段时间系统几乎处于不可用状态,Annoying!
oom_killer
默认配置下,当没有内存可以用而又要用到内存时,Linux内核的oom_killer(out of memory killer)会扫描一遍占用内存最多的程序(可能有多个,比如VirtualBox和Firefox一起悲剧),并把它们结束掉。
这种扫描其实代价还是挺大的,可以选择让oom_killer不要扫描出用内存最多的进程,只是解决掉申请内存的那些进程:
sysctl -w vm.oom_kill_allocating_task = 1
使用这样的设置,oom_killer不会去花时间寻找占内存最多的进程杀掉,VirtualBox和Firefox就有一定机会幸免。但是在内存 用完的那一瞬间,谁去申请或者使用一片空白的内存,谁就会悲剧,而且可能是几个进程一起被杀掉,充满了不可预测性(比如,Xorg被杀掉,于是许多程序连 带就挂掉了,再比如后台的mysqld被杀掉也会带来许多不方便),而且也没有避免pdflush在最后关头让硬盘灯狂闪的情况。
总之,oom_killer很不和谐,最好不要让它出场。在这一点上,openSolaris似乎做的就比较好,从外表上看,在内存不够的时候,系 统不会去主动杀掉正在运行的程序,而是拒绝运行新的程序,并且运行中的程序如果申请内存的话就会被暂停,直至有内存可以给它的时候才继续运行。
overcommit
那么系统为什么不能提前检测到内存用完呢,malloc是有可能返回NULL的啊?现在的操作系统中,允许过分地申请内存,如果只是申请内存而没有实际使用的话,可以申请到比实际内存大许多的空间(比如用malloc申请内存,while(1) malloc(x);
这样的程序都可以运行好长时间),只有一旦开始用(比如用memset去填),才会计入真正的内存使用,这时候如果内存真的不够了,那么oom_killer就上场了。
目前的Linux提供了一些选项用来调整这种内存策略 :-)
默认情况下,vm.overcommit_memory = 0
,这时候可以申请到比较多的内存,但是仍然会在一定的时候申请失败。
还有更宽松一些的,如果 vm.overcommit_memory = 1
,所有的malloc都会无条件成功 相当可怕的世界。
最后一种选择就是这个了:
sysctl -w vm.overcommit_memory = 2
这时候,对申请内存总数有严格的限制,malloc会在超过限制的时候返回NULL,应用程序可以适当处理这种情况,而oom_killer再也不会蹦出来了,pdflush也不会让硬盘转得系统没响应,如果一个程序不能适当处理这种情况,就立即挂掉,干净利落。
但是这也有坏处,这时候参数vm.overcommit_ratio
也会起作用,默认是50,意思是只能分配到实际物理内存的50%。如果没有交换区的话,overcommit_ratio
设置得小就会很悲剧,几乎什么都做不了。
那把它设置成100,事情就非常和谐了?没有这样简单,这里的限制是申请内存总数的限制,如果申请了却没有实际用到的话,也是计入总数的。这样的话,实际内存没有用完,程序也很有可能申请不到内存,有一些内存就被浪费了。
虽然overcommit_ratio
可以被设置成大于100的数,但是到底设置成多少确是个棘手的问题,设置大了,就和没有限制一样,内存用完时硬盘会狂转,系统会失去响应一段时间,oom_killer有可能会上场,设置小了,有可能几百兆的内存被白白浪费了
检查内存信息可以看到:
% cat /proc/meminfo
MemTotal: 2064616 kB
MemFree: 1556672 kB
....
CommitLimit: 2064616 kB
Committed_AS: 769068 kB
....
其中Committed_AS是程序申请的内存总和,不能超过CommitLimit。很明显地看到Committed_AS+MemFree比MemTotal大,看起来把CommitLimit设置成Committed_AS+MemFree比较合适。
不过这个时候,CommitLimit是只受overcommit_ratio
影响的,内存使用状态在动态变化,只好写一个程序来动态修改overcommit_ratio
了。
最后我写了这样的一段C的小程序,每一秒设置一次overcommit_ratio
。在目前版本的Linux内核(2.6.31)上i686平台可用:
#define _GNU_SOURCE 1
#include <unistd .h>
#include <stdio .h>
#include <stdlib .h>
#include <err .h>
#include <errno .h>
#include <string .h>
#define errexit(status, info) fprintf(stderr, "%s: %s\n", program_invocation_name, info), exit(status);
FILE *fp_meminfo;
void set_overcommitted_limit(int value)
{
char new_value[32];
int old_len = 0;
FILE *fp_overcommit_ratio;
if (!(fp_overcommit_ratio = fopen("/proc/sys/vm/overcommit_ratio", "w")))
err(-4, "can't write /proc/sys/vm/overcommit_ratio");
fprintf(fp_overcommit_ratio, "%d", value);
fclose(fp_overcommit_ratio);
}
int main(int argc, char const* argv[])
{
char item_name[32];
int item_value;
int mem_free, mem_total, committed_as, buffers, cached, item_count, i;
char essential_names[][32] = {"MemTotal", "MemFree", "Committed_AS", "Cached"};
int essential_values[sizeof(essential_names) / sizeof(essential_names[0])];
for(;;sleep(1)) {
if (!(fp_meminfo = fopen("/proc/meminfo", "r")))
err(-2, "can't read /proc/meminfo");
for (memset(essential_values, -1, sizeof(essential_values)),
item_count = sizeof(essential_values) / sizeof(essential_values[0]);
item_count; ) {
if (feof(fp_meminfo)) errexit(-3, "can't read all essential information");
fscanf(fp_meminfo, " %31[^:]%*[^ ]%d%*[^\n]", item_name, &item_value);
for(i = 0; i < sizeof(essential_values) / sizeof(essential_values[0]); i++) {
if (essential_values[i] == -1 &&
strcmp(essential_names[i], item_name) == 0) {
essential_values[i] = item_value;
--item_count;
break;
}
}
}
set_overcommitted_limit(
(essential_values[1] + essential_values[2] + essential_values[3] / 3)
* 100 / essential_values[0] + 1);
fclose(fp_meminfo);
}
return 0;
}
这段程序需要管理员权限运行,把它设置成开机必执行工具之一,同时在/etc/sysctl.conf
上加上相关设置,就十分和谐啦
就这一方面,可能还是openSolaris的做法最和谐,不过仅仅这一点并不能让我投奔openSolaris,把它作为日常使用的系统。默默地期待openSolaris和Linux都越来越好吧~
oom_killer的更多相关文章
- Android 操作系统的内存回收机制(转载)
Android 操作系统的内存回收机制(转载) Android APP 的运行环境 Android 是一款基于 Linux 内核,面向移动终端的操作系统.为适应其作为移动平台操作系统的特殊需要,谷歌对 ...
- NUMA架构的CPU -- 你真的用好了么?
本文从NUMA的介绍引出常见的NUMA使用中的陷阱,继而讨论对于NUMA系统的优化方法和一些值得关注的方向. 文章欢迎转载,但转载时请保留本段文字,并置于文章的顶部 作者:卢钧轶(cenalulu) ...
- linux 终端报错 Out of memory: Kill process[PID] [process name] score问题分析
从Out of memory来看是内存超出了,后面的 Kill process[PID] [process name] score好像和进程有关了,下面我们就一起来看看linux 终端报错 Out o ...
- yii 操作session和cookie
一,在Yii中使用session 1,CHttpSession 与原生态php5的session使用差别是,php5使用session_start();$_session['key'] = $valu ...
- vm内核参数优化设置
http://www.cnblogs.com/wjoyxt/archive/2014/06/08/3777042.html (1)vm.overcommit_memory 执行grep -i com ...
- 如何用Java编写一段代码引发内存泄露
本文来自StackOverflow问答网站的一个热门讨论:如何用Java编写一段会发生内存泄露的代码. Q:刚才我参加了面试,面试官问我如何写出会发生内存泄露的Java代码.这个问题我一点思路都没有, ...
- 计算机体系结构-内存调优IPC OOMK
man ipc [root@server1 proc]# man ipcIPC(2) Linux Programmer’s Manual ...
- /proc/sys/ 下内核参数解析
http://blog.itpub.net/15480802/viewspace-753819/ http://blog.itpub.net/15480802/viewspace-753757/ ht ...
- Android 操作系统的内存回收机制[转]
转自:http://www.ibm.com/developerworks/cn/opensource/os-cn-android-mmry-rcycl/ Android APP 的运行环境 Andro ...
随机推荐
- CDOJ 1287 MC挖矿世界(Spfa+set优化)
题目大意:原题链接 解题思路:此题要求多点最短距离,但是直接套用floyd会超时. 然后我们想直接从每一个点开始bfs就好了,但是还是会TLE,为什么呢? 因为你访问了很多次没有意义的地方,因为有些点 ...
- Spark SQL慕课网日志分析(1)--系列软件(单机)安装配置使用
来源: 慕课网 Spark SQL慕课网日志分析_大数据实战 目标: spark系列软件的伪分布式的安装.配置.编译 spark的使用 系统: mac 10.13.3 /ubuntu 16.06,两个 ...
- 这几天添加ccbi 出现的问题
父类是一个ccbi...在父类的onNodeLoaded 里面添加子类的ccbi ... 出现了父类为空的情况...获取不到时间轴..动画为空... 需要在父类的onEnter里面写添加子类的ccbi ...
- 50条常用liunx命令整理
1.pwd命令 :确定自己在那个目录 使用方法:在liunx命令输入框里面输入pwd,自动就会显示出自己现在在那个目录下 操作截图: 此时正处在root目录里面 2.cd命令:切换目录的意思 使用方法 ...
- python的socket网络编程(二)
(注:本文部分内容摘自互联网,由于作者水平有限,不足之处,还望留言指正.) 国庆八天假,已过去3天了,加上明天又是中秋,还是决定在今晚把之前想写的东西写完.国庆节在宁波老家,吃好喝好睡好,就是没有好好 ...
- sparkSQL实战详解
摘要 如果要想真正的掌握sparkSQL编程,首先要对sparkSQL的整体框架以及sparkSQL到底能帮助我们解决什么问题有一个整体的认识,然后就是对各个层级关系有一个清晰的认识后,才能真正的 ...
- Redis 数据结构-字符串源码分析
相关文章 Redis 初探-安装与使用 Redis常用指令 本文将从以下几个部分进行介绍 1.前言 2.常用命令 3.字符串结构 4.字符串实现 5.命令是如果操作字符串的 前言 平时在使用 Redi ...
- J2Cache 和普通缓存框架有何不同,它解决了什么问题?
不少人看到 J2Cache 第一眼时,会认为这就是一个普普通通的缓存框架,和例如 Ehcache.Caffeine .Spring Cache 之类的项目没什么区别,无非是造了一个新的轮子而已.事实上 ...
- 如何安装python .whl包
1.最简单的办法是是python -mpip install *** 配置过环境变量也可以 pip install *** 但是由于墙的原因,很大概率失败.可以找到对应网站下载对应的.whl 2.下载 ...
- 20145312《Java程序设计》课程总结
20145312<Java程序设计>课程总结 每周读书笔记链接汇总 20145312<Java程序设计>第一周学习总结 20145312<Java程序设计>第二周学 ...