跳转至

过度分配的理解

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时自动重启系统。这都是有风险的机制,重启有可能造成业务中断,杀死进程也有可能导致业务中断

vm.overcommit_memory 参数

vm.overcommit_memory = 0

vm.overcommit_memory = 1

vm.overcommit_memory = 2

0 默认设置,允许用户轻微的overcommit.

它允许overcommit,但过于明目张胆的overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存。单次申请的内存大小不能超过 【free memory + free swap + pagecache的大小 + SLAB中可回收的部分】,否则本次申请就会失败。

1 允许overcommit

即允许分配所有的物理内存,而不管当前的内存状态如何。

使用这个设置会增大内存超载的可能性,但也可以增强大量使用内存任务的性能。

2 不允许过度 overcommit

当系统分配的内存超过swap+N%*物理RAM(N%由vm.overcommit_ratio决定)时,会拒绝分配

vm.overcommit_ratio 参数

vm.overcommit_memory=2才生效

vm.overcommit_ratio 是内核参数,缺省值是50,表示物理内存的50%。如果你不想使用比率,也可以直接指定内存的字节数大小,通过另一个内核参数 vm.overcommit_kbytes 即可;

公式:CommitLimit = (Physical RAM * vm.overcommit_ratio / 100) + Swap

如果使用了huge pages,那么需要从物理内存中减去,公式变成: CommitLimit = ([total RAM] – [total huge TLB RAM]) * vm.overcommit_ratio / 100 + swap

详见:What is the formula to calculate "CommitLimit" value on Red Hat Enterprise Linux 5 and 6 ? - Red Hat Customer Portal

查看系统 overcommit 信息

# cat /proc/meminfo |grep -i commit

CommitLimit:    90971304 kB
Committed_AS:   64872556 kB

CommitLimit:最大能分配的内存,具体的值是 SWAP内存大小 + 物理内存 * overcommit_ratio / 100。CommitLimit 就是overcommit的阈值,申请的内存总数超过CommitLimit的话就算是overcommit。(vm.overcommit_memory=2)时就会禁止overcommit

Committed_AS:当前已经分配的内存大小。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),意思是_内存申请_占_物理内存与交换区之和_的百分比。
$ 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

理解Linux的memory overcommit | Linux Performance