Memory Overcommit的意思是操作系统承诺给进程的内存大小超过了实际可用的内存。一个保守的操作系统不会允许memory overcommit,有多少就分配多少,再申请就没有了,这其实有些浪费内存,因为进程实际使用到的内存往往比申请的内存要少,比如某个进程malloc()了200MB内存,但实际上只用到了100MB,按照UNIX/Linux的算法,物理内存页的分配发生在使用的瞬间,而不是在申请的瞬间,也就是说未用到的100MB内存根本就没有分配,这100MB内存就闲置了。下面这个概念很重要,是理解memory overcommit的关键:commit(或overcommit)针对的是内存申请,内存申请不等于内存分配,内存只在实际用到的时候才分配。

Linux是允许memory overcommit的,只要你来申请内存我就给你,寄希望于进程实际上用不到那么多内存,但万一用到那么多了呢?那就会发生类似“银行挤兑”的危机,现金(内存)不足了。Linux设计了一个OOM killer机制(OOM = out-of-memory)来处理这种危机:挑选一个进程出来杀死,以腾出部分内存,如果还不够就继续杀…也可通过设置内核参数 vm.panic_on_oom 使得发生OOM时自动重启系统。这都是有风险的机制,重启有可能造成业务中断,杀死进程也有可能导致业务中断,我自己的这个小网站就碰到过这种问题,参见前文。所以Linux 2.6之后允许通过内核参数 vm.overcommit_memory 禁止memory overcommit。

内核参数 vm.overcommit_memory 接受三种取值:

  • 0 – Heuristic overcommit handling. 这是缺省值,它允许overcommit,但过于明目张胆的overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存。Heuristic的意思是“试探式的”,内核利用某种算法(对该算法的详细解释请看文末)猜测你的内存申请是否合理,它认为不合理就会拒绝overcommit。
  • 1 – Always overcommit. 允许overcommit,对内存申请来者不拒。
  • 2 – Don’t overcommit. 禁止overcommit。

关于禁止overcommit (vm.overcommit_memory=2) ,需要知道的是,怎样才算是overcommit呢?kernel设有一个阈值,申请的内存总数超过这个阈值就算overcommit,在/proc/meminfo中可以看到这个阈值的大小:

 
1
2
3
# grep -i commit /proc/meminfo
CommitLimit:     5967744 kB
Committed_AS:    5363236 kB

CommitLimit 就是overcommit的阈值,申请的内存总数超过CommitLimit的话就算是overcommit。
这个阈值是如何计算出来的呢?它既不是物理内存的大小,也不是free memory的大小,它是通过内核参数vm.overcommit_ratio或vm.overcommit_kbytes间接设置的,公式如下:
【CommitLimit = (Physical RAM * vm.overcommit_ratio / 100) + Swap】

注:
vm.overcommit_ratio 是内核参数,缺省值是50,表示物理内存的50%。如果你不想使用比率,也可以直接指定内存的字节数大小,通过另一个内核参数 vm.overcommit_kbytes 即可;
如果使用了huge pages,那么需要从物理内存中减去,公式变成:
CommitLimit = ([total RAM] – [total huge TLB RAM]) * vm.overcommit_ratio / 100 + swap
参见https://access.redhat.com/solutions/665023

/proc/meminfo中的 Committed_AS 表示所有进程已经申请的内存总大小,(注意是已经申请的,不是已经分配的),如果 Committed_AS 超过 CommitLimit 就表示发生了 overcommit,超出越多表示 overcommit 越严重。Committed_AS 的含义换一种说法就是,如果要绝对保证不发生OOM (out of memory) 需要多少物理内存。

“sar -r”是查看内存使用状况的常用工具,它的输出结果中有两个与overcommit有关,kbcommit 和 %commit:
kbcommit对应/proc/meminfo中的 Committed_AS;
%commit的计算公式并没有采用 CommitLimit作分母,而是Committed_AS/(MemTotal+SwapTotal),意思是_内存申请_占_物理内存与交换区之和_的百分比。

 
1
2
3
4
$ sar -r
 
05:00:01 PM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
05:10:01 PM    160576   3648460     95.78         0   1846212   4939368     62.74   1390292   1854880         4

附:对Heuristic overcommit算法的解释

内核参数 vm.overcommit_memory 的值0,1,2对应的源代码如下,其中heuristic overcommit对应的是OVERCOMMIT_GUESS:

 
1
2
3
4
5
源文件:source/include/linux/mman.h
 
#define OVERCOMMIT_GUESS                0
#define OVERCOMMIT_ALWAYS               1
#define OVERCOMMIT_NEVER                2

Heuristic overcommit算法在以下函数中实现,基本上可以这么理解:
单次申请的内存大小不能超过 【free memory + free swap + pagecache的大小 + SLAB中可回收的部分】,否则本次申请就会失败。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
源文件:source/mm/mmap.c 以RHEL内核2.6.32-642为例
 
0120 /*
0121  * Check that a process has enough memory to allocate a new virtual
0122  * mapping. 0 means there is enough memory for the allocation to
0123  * succeed and -ENOMEM implies there is not.
0124  *
0125  * We currently support three overcommit policies, which are set via the
0126  * vm.overcommit_memory sysctl.  See Documentation/vm/overcommit-accounting
0127  *
0128  * Strict overcommit modes added 2002 Feb 26 by Alan Cox.
0129  * Additional code 2002 Jul 20 by Robert Love.
0130  *
0131  * cap_sys_admin is 1 if the process has admin privileges, 0 otherwise.
0132  *
0133  * Note this is a helper function intended to be used by LSMs which
0134  * wish to use this logic.
0135  */
0136 int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
0137 {
0138         unsigned long free, allowed;
0139
0140         vm_acct_memory(pages);
0141
0142         /*
0143          * Sometimes we want to use more memory than we have
0144          */
0145         if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)
0146                 return 0;
0147
0148         if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { //Heuristic overcommit算法开始
0149                 unsigned long n;
0150
0151                 free = global_page_state(NR_FILE_PAGES); //pagecache汇总的页面数量
0152                 free += get_nr_swap_pages(); //free swap的页面数
0153
0154                 /*
0155                  * Any slabs which are created with the
0156                  * SLAB_RECLAIM_ACCOUNT flag claim to have contents
0157                  * which are reclaimable, under pressure.  The dentry
0158                  * cache and most inode caches should fall into this
0159                  */
0160                 free += global_page_state(NR_SLAB_RECLAIMABLE); //SLAB可回收的页面数
0161
0162                 /*
0163                  * Reserve some for root
0164                  */
0165                 if (!cap_sys_admin)
0166                         free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10); //给root用户保留的页面数
0167
0168                 if (free > pages)
0169                         return 0;
0170
0171                 /*
0172                  * nr_free_pages() is very expensive on large systems,
0173                  * only call if we're about to fail.
0174                  */
0175                 n = nr_free_pages(); //当前free memory页面数
0176
0177                 /*
0178                  * Leave reserved pages. The pages are not for anonymous pages.
0179                  */
0180                 if (n <= totalreserve_pages)
0181                         goto error;
0182                 else
0183                         n -= totalreserve_pages;
0184
0185                 /*
0186                  * Leave the last 3% for root
0187                  */
0188                 if (!cap_sys_admin)
0189                         n -= n / 32;
0190                 free += n;
0191
0192                 if (free > pages)
0193                         return 0;
0194
0195                 goto error;
0196         }
0197
0198         allowed = vm_commit_limit();
0199         /*
0200          * Reserve some for root
0201          */
0202         if (!cap_sys_admin)
0203                 allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
0204
0205         /* Don't let a single process grow too big:
0206            leave 3% of the size of this process for other processes */
0207         if (mm)
0208                 allowed -= mm->total_vm / 32;
0209
0210         if (percpu_counter_read_positive(&vm_committed_as) < allowed)
0211                 return 0;
0212 error:
0213         vm_unacct_memory(pages);
0214
0215         return -ENOMEM;
0216 }

参考:
https://www.kernel.org/doc/Documentation/vm/overcommit-accounting
https://www.win.tue.nl/~aeb/linux/lk/lk-9.html
https://www.kernel.org/doc/Documentation/sysctl/vm.txt
http://lwn.net/Articles/28345/

转载自:

http://linuxperf.com/?p=102

Linux 理解Linux的memory overcommit 与 OOM Killer的更多相关文章

  1. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #16 OOM Killer的运行与结构

    HACK #16 OOM Killer的运行与结构(1) 本节介绍OOM Killer的运行与结构. Linux中的Out Of Memory(OOM) Killer功能作为确保内存的最终手段,可以在 ...

  2. oom killer 详解

    一.oom killer理解和日志分析:知识储备 oom killer日志分析,这是前篇,准备一些基础知识 带着问题看: 1.什么是oom killer 是Linux内核设计的一种机制,在内存不足的时 ...

  3. 理解和配置 Linux 下的 OOM Killer

    原文:http://www.vpsee.com/2013/10/how-to-configure-the-linux-oom-killer/ 最近有位 VPS 客户抱怨 MySQL 无缘无故挂掉,还有 ...

  4. [转]理解和配置 Linux 下的 OOM Killer

    最近有位 VPS 客户抱怨 MySQL 无缘无故挂掉,还有位客户抱怨 VPS 经常死机,登陆到终端看了一下,都是常见的 Out of memory 问题.这通常是因为某时刻应用程序大量请求内存导致系统 ...

  5. 理解和配置 Linux 下的 OOM Killer【转】

    本文转载自:http://www.vpsee.com/2013/10/how-to-configure-the-linux-oom-killer/ 最近有位 VPS 客户抱怨 MySQL 无缘无故挂掉 ...

  6. [Android Memory] Linux下malloc函数和OOM Killer

    http://www.linuxidc.com/Linux/2010-09/28364.htm Linux下malloc函数主要用来在用户空间从heap申请内存,申请成功返回指向所分配内存的指针,申请 ...

  7. Linux系统OOM killer机制详解

    介绍: Linux下面有个特性叫OOM killer(Out Of Memory killer),会在系统内存耗尽的情况下出现,选择性的干掉一些进程以求释放一些内存.广大从事Linux方面的IT农民工 ...

  8. 深入理解Linux内存分配

    深入理解Linux内存分配 为了写一个用户层程序,你也许会声明一个全局变量,这个全局变量可能是一个int类型也可能是一个数组,而声明之后你有可能会先初始化它,也有可能放在之后用到它的时候再初始化.除此 ...

  9. Linux OOM killer 与相关参数详解

    一.前言 本文是描述Linux virtual memory运行参数的第二篇,主要是讲OOM相关的参数的.为了理解OOM参数,第二章简单的描述什么是OOM.如果这个名词对你毫无压力,你可以直接进入第三 ...

随机推荐

  1. laravel框架视图中常用的逻辑结构forlese,foreach,ifelse等

    if 和else @if($name === 1) 这个数字是1 @else 这个数字非1 @endif switch @switch($name) @case(1) 变量name == 1 @bre ...

  2. python使用ORM之如何调用多对多关系

    在models.py中,我创建了两张表,他们分别是作者表和书籍表,且之间的关系是多对多. # 书 class Book(models.Model): id = models.AutoField(pri ...

  3. SAS学习笔记50 SAS数据集索引

    在没有索引的情况下,SAS是一条接一条的扫描观测:有索引时,直接跳到该索引对应的观测所在位置.总结一句话就是:节省时间,节省内存,提高效率 当然并不是任何情况下使用索引都能提高工作效率,因为建立索引本 ...

  4. pat天梯赛练习集合 L3-007 天梯地图

    加了一些花的最短路,点的个数为500不需要堆优化,改一下dij的判断条件就可以了. 上代码: #include <iostream> #include <cstring> #i ...

  5. (转) [组合数学] 第一类,第二类Stirling数,Bell数

    一.第二类Stirling数 定理:第二类Stirling数S(p,k)计数的是把p元素集合划分到k个不可区分的盒子里且没有空盒子的划分个数. 证明:元素在哪些盒子并不重要,唯一重要的是各个盒子里装的 ...

  6. Spring Boot整合Spring Security自定义登录实战

    本文主要介绍在Spring Boot中整合Spring Security,对于Spring Boot配置及使用不做过多介绍,还不了解的同学可以先学习下Spring Boot. 本demo所用Sprin ...

  7. [NOIP11.1模拟赛]补番报告

    Preface 昨天开始补某科学的超电磁炮S 感觉今天就好了点,炮姐赛高 T1 一开始一直想欧拉定理&ex欧拉定理,结果估计70分,数组开小了GG,看了正解发现是我学傻了 T2 一看就是数据结 ...

  8. 删除MRP单据

    select *into newtable from a_mplist 把a_mplist的表中的数据复制到newtable表中结构也是一样的 insert into newtable select ...

  9. redis过期事件回调函数,与有序集合

    https://cloud.tencent.com/developer/article/1347437  python中的Redis键空间通知(过期回调) set notify-keyspace-ev ...

  10. javascript_08-while 和 do while

    while 和 do while for 当循环次数已知 while 先判断再执行 do while 先执行一次再判断 //1-100 之间所有数字的和 //while // var i = 1; / ...