计算分数的方法

在OOM Killer计算分数时要考虑很多方面。首先要针对每个进程确认下列1~9个事项再计算分数。

1.首先,计算分数时是以进程的虚拟内存大小为基准的。虚拟内存大小可以使用ps命令的VSZ或/proc/<PID>/status的VmSize[1]。来确认。对于正在消耗虚拟内存的进程,其最初的得分较高。单位是将1KB作为1个得分。消耗1GB内存的进程,得分约为1 000 000。

2.如果进程正在执行swapoff系统调用,则得分设置为最大值(unsigned long的最大值)。这是因为禁用swap的行为与消除内存不足是相反的,会立刻将其作为OOM Killer的对象进程。

3.如果是母进程,则将所有子进程内存大小的一半作为分数。

4.根据进程的CPU使用时间和进程启动时间调整得分。这是因为在这里认为越是长时间运行或从事越多工作的进程越重要,需保持得分较低。

首先,用得分除以CPU使用时间(以10秒为单位)的平方根。如果CPU使用时间为90秒,由于以10秒为单位,因此就是用得分除以9的平方根“3”。另外,根据进程启动开始的时间也可以调整得分。用得分除以启动时间(以1000秒为单位)的平方根的平方根。如果是持续运行16 000秒的进程,则用得分除以16的平方根“4”的平方根“2”。越是长时间运行的进程就越重要。

小贴士:虽然源代码的备注中写有以10秒为单位、以1000秒为单位,但是实际上在位运算中是以8和1024为单位来计算。

5.对于通过nice命令等将优先级设置得较低的进程,要将得分翻倍。nice-n中设置为1~19的命令的得分翻倍。

6.特权进程普遍较为重要,因此将其得分设置为1/4。

7.通过capset(3)等设置了功能(capability)CAP_SYS_RAWIO[2]的进程,其得分为1/4。将直接对硬件进行操作的进程判断为重要进程。

8.关于Cgroup,如果进程只允许与促使OOM Killer运行的进程所允许的内存节点完全不同的内存节点,则其得分为1/8。

9.最后通过proc文件系统oom_adj的值调整得分。

依据以上规则,为所有进程打分,向得分最高的进程发送信号SIGKILL(到Linux 2.6.10为止,在设置了功能CAP_SYS_RAWIO的情况下,发送SIGTERM,在没有设置的情况下,发送SIGKILL)。

各进程的得分可以使用/proc/<PID>/oom_score来确认。

但是init(PID为1的)进程不能成为OOM Killer的对象。当成为对象的进程包含子进程时,先向其子进程发送信号。

向成为对象的进程发送信号后,对于引用系统的全线程,即使线程组(TGID)不同,如果存在与对象进程共享相同内存空间的进程,则也向这些进程发送信号。

[1]有时/proc/<PID>status的VmSize与计算出的分值多少有些差异。

[2]默认为已设置。