当前位置:C++技术网 > 资讯 > Linux系统内存不足守护者OOM Killer

Linux系统内存不足守护者OOM Killer

更新时间:2017-08-18 08:34:38浏览次数:1+次

        OOM Killer 是Out Of Memory Killer的简称。OOMKiller功能作为确保内存的最终手段,可以在耗尽系统内存或交换区后,向进程发送信号,强制终止该进程。 OOM Killer通过终止进程来确保空闲内存,以确保Linux系统有足够的系统保持稳定的运行。而要kill哪个进程,则是有一套算法的。简单的理解就是,计算每一个进程的内存使用得到一个分数,分数最高的就会被干掉。
计算分数的算法如下:
    OOM Killer在内存耗尽时,会查看所有进程,并分别为每个进程计算分数。将信号发送给分数最高的进程。 
    计算分数的方法 
    在OOM Killer计算分数时要考虑很多方面。首先要针对每个进程确认下列1~9个事项再计算分数。 
1. 首先,计算分数时是以进程的虚拟内存大小为基准的。虚拟内存大小可以使用ps命令的VSZ或/proc/<PID>/status的 VmSize注2来确认。对于正在消耗虚拟内存的进程,其最初的得分较高。单位是将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注3的进程,其得分为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)不同,如果存在与对象进程共享相同内存空间的进程,则也向这些进程发送信号。 
        被OOM Killer 杀死的进程是不会产生core文件的,所以我们需要通过其他方式来寻找蛛丝马迹。
    我们可以很轻松的就可以触发OOM Killer,那就是不停的分配内存,直到内存耗尽时,OOM Killer就会干掉你的进程了。通过测试发现,我一度new了数GB的内存,才触发OOM Killer。因为申请分配内存的速度实在是太快了,估计虽然已经申请了这么多,实际上并没有得到这么多,也就是申请的内存会失败。但是不论怎么样,大量的申请,还是让内存慢慢枯竭。Linux系统为了让系统能够工作正常,最后就干掉了我的进程。