overcommit和oom-killer

今天遇到一个很怪异的情况: 有个线上服务,总是莫名其妙的重启。该服务已经岁月静好运行了几个月了,而且观察日志也没有发现log。最终发现,是服务器内存不足,操作系统会杀一些进程(用户态进程,不是内核线程)释放内存。这就是所谓的oom(out of memory)-killer。

1. 什么是overcommit

要理解oom-killer,就要先理解overcommit机制。

在Unix中,当一个用户进程使用malloc()函数申请内存时,假如返回值是NULL,则这个进程知道当前没有可用内存空间,就会做相应的处理工作。许多进程会打印错误信息并退出。

Linux使用另外一种处理方式,它对大部分申请内存的请求都回复"yes",以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存。这种技术叫做Overcommit。也就是说malloc的时候不真的分配内存,而是在memset的时候分配。

当内存不足时,会发生OOM killer(OOM=out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存。

Linux下overcommit有三种策略:

  • 0: 一种启发式的策略,内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
  • 1: 允许overcommit
  • 2: 不允许overcommit,即超过CommitLimit的数值就会申请内存失败。CommitLimit只在overcommit_memory=2时有效。

策略方法查看方法如下:

$ cat /proc/sys/vm/overcommit_memory
0

CommitLimit的值可以通过命令查看,其中Committed_AS表示当前已经使用的内存。

grep -i commit /proc/meminfo
CommitLimit:     6201492 kB
Committed_AS:    5770836 kB

其中, CommitLimit = swap(交换内存) + mem(物理内存) * overcommit_ratio / 100。这和CommitLimit的数值是吻合的。

overcommit_ratio查看方法如下:

$ cat /proc/sys/vm/overcommit_ratio
50

可以看到,overcommit_ratio为50,即 CommitLimit = swap + mem * 50 / 100

2. 发生oom-killer时,哪个进程优先被杀掉

这是进程的oom_score决定,而oom_score与oom_adj有关。oom_adj的可调值为15到-16,其中15最大-16最小,-17为禁止使用OOM。

可以查看 /proc/PID/oom_score 和 /proc/PID/oom_adj

你可能感兴趣的:(overcommit和oom-killer)