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

相關文章
相關標籤/搜索