oom-killer, 杀掉进程的凶手

今天发现进程一直被杀掉,几经排查,最后确认是被oom-killer杀掉了。node

在内核检测到系统内存不足后,会触发oom-killer,挑选最占用内存的进程杀掉。linux

Linux 分配内存策略

Linux内核根据应用程序的要求来分配内存,因为进程实际上并不会将分配的内存所有使用,因此,为了提升性能,内核采用了一种过分分配内存(over-commit-memory)的策略,来间接利用进程的空闲内存,提升内存的使用效率。通常来讲,这没问题。但若是大多数进程都耗光本身的内存,就有麻烦了。所以此时,全部应用程序的内存之和大于物理内存。因此,必须杀掉一部分进程,通常来讲,是选内存占用最大的进程杀掉。算法

挑选原理

挑选的过程由linux/mm/oom_kill.c里的 oom_badness() 函数决定,挑选的算法很直接:是那个最占用内存的进程。
/**
 * oom_badness - heuristic function to determine which candidate task to kill
 * @p: task struct of which task we should calculate
 * @totalpages: total present RAM allowed for page allocation
 *
 * The heuristic for determining which task to kill is made to be as simple and
 * predictable as possible.  The goal is to return the highest value for the
 * task consuming the most memory to avoid subsequent oom failures.
 */
unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
              const nodemask_t *nodemask, unsigned long totalpages)
{
    long points;
    long adj;

    if (oom_unkillable_task(p, memcg, nodemask))
        return 0;

    p = find_lock_task_mm(p);
    if (!p)
        return 0;

    adj = (long)p->signal->oom_score_adj;
    if (adj == OOM_SCORE_ADJ_MIN) {
        task_unlock(p);
        return 0;
    }

    /*
     * The baseline for the badness score is the proportion of RAM that each
     * task's rss, pagetable and swap space use.
     */
    points = get_mm_rss(p->mm) + p->mm->nr_ptes +
         get_mm_counter(p->mm, MM_SWAPENTS);
    task_unlock(p);

    /*
     * Root processes get 3% bonus, just like the __vm_enough_memory()
     * implementation used by LSMs.
     */
    if (has_capability_noaudit(p, CAP_SYS_ADMIN))
        adj -= 30;

    /* Normalize to oom_score_adj units */
    adj *= totalpages / 1000;
    points += adj;

    /*
     * Never return 0 for an eligible task regardless of the root bonus and
     * oom_score_adj (oom_score_adj can't be OOM_SCORE_ADJ_MIN here).
     */
    return points > 0 ? points : 1;
}

避免被杀掉的办法

从上面的代码里能够看到 oom_badness() 给每一个进程打分,根据 points 的高低来决定杀哪一个进程,分数越低越不会被杀掉。
这个 points 能够根据 adj 调节,root 权限的进程一般被认为很重要,不该该被轻易杀掉,因此打分的时候能够获得 3% 的优惠(adj -= 30; 分数越低越不容易被杀掉)。
咱们能够在用户空间经过操做每一个进程的 oom_adj 内核参数来使得进程不容易被 OOM killer 选中杀掉。好比,若是不想 test进程被轻易杀掉的话能够找到 test运行的进程号后,调整 oom_score_adj 为 -15(注意 points 越小越不容易被杀):bash

# ps aux | grep test
test    2334  1.6  2.1 623800 4876 ?        Ssl  09:52   0:00 /usr/sbin/test

# cat /proc/2334/oom_score_adj
0
# echo -15 > /proc/2334/oom_score_adj

固然,也能够彻底关闭 OOM killer,但线上生产环境最好不要这么作。less

相关文章
相关标签/搜索