今天發現進程一直被殺掉,幾經排查,最後確認是被oom-killer殺掉了。node
在內核檢測到系統內存不足後,會觸發oom-killer,挑選最佔用內存的進程殺掉。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