當系統記憶體耗盡,Linux 核心會觸發 OOM Killer(Out-of-Memory Killer)犧牲進程以求生存。預設行為是掃描佔用記憶體最多的進程並將其終止,但這過程耗時且不可控,可能誤殺關鍵服務(如 MySQL、Xorg)。本文深入剖析 OOM 行為,並介紹透過 vm.overcommit_memory 徹底避免 OOM 的策略。
oom_score,開銷大。sysctl -w vm.oom_kill_allocating_task=1
直接殺掉請求記憶體失敗的進程,避免全域掃描。但缺點是引入隨機性:誰剛好在記憶體耗盡瞬間申請記憶體,誰就會被殺,可能連帶摧毀多個關鍵進程。
Linux 支援三種過度提交模式:
| 值 | 模式 | 說明 |
|---|---|---|
| 0 | 啟發式 | 預設。允許適度過度提交,但在某個臨界點拒絕分配。 |
| 1 | 總是允許 | 所有 malloc() 成功,極度危險,實際使用時才觸發 OOM。 |
| 2 | 嚴格模式 | 推薦。核心拒絕超過 CommitLimit 的分配請求,malloc() 返回 NULL,應用程式可自行處理,OOM Killer 永不出場。 |
sysctl -w vm.overcommit_memory=2
# 永久生效
echo "vm.overcommit_memory=2" >> /etc/sysctl.conf
sysctl -p
嚴格模式下,總可提交記憶體上限 CommitLimit = 物理記憶體 × overcommit_ratio / 100 + Swap。預設 overcommit_ratio=50(僅 50% 物理記憶體),若無 Swap 幾乎無法運行。
建議設為 100 或略高(如 120),但需權衡:
可透過 /proc/meminfo 中的 Committed_AS(已提交)與 MemFree(剩餘)估算合適值:
CommitLimit ≈ Committed_AS + MemFree
cat /proc/meminfo | grep -E 'CommitLimit|Committed_AS|MemFree|MemTotal'
嚴格模式下,系統不再因記憶體耗盡而卡頓、磁碟狂轉、OOM Killer 亂殺,應用程式收到 ENOMEM 可優雅降級或退出,系統穩定性大幅提升。