首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL OOM 系列二:深入剖析 Linux OOM Killer 機制

     編輯:MySQL 資料庫相關知識

OOM Killer 選擇犧牲進程的邏輯

並非單純殺佔用記憶體最多的進程,而是由 /proc//oom_score 決定,經內核 oom_badness() 函數計算。核心原則:

  1. 損失最少工作量
  2. 回收最大記憶體
  3. 不殺無辜的大量佔用記憶體進程
  4. 殺最少數量進程(通常一個)
  5. 符合用戶預期(算法經精心調優)

Badness 計分詳解

基礎分:進程實際物理記憶體(RSS)

points = p->mm->total_vm;

不包含 Swap,物理記憶體越大分越高,越易被殺。

子進程記憶體歸屬父進程

if (chld->mm != p->mm && chld->mm)
    points += chld->mm->total_vm;

防止 Fork 型服務器產生大量子進程洩漏記憶體。

運行時間與 CPU 時間懲罰係數

s = int_sqrt(cpu_time); if (s) points /= s;
s = int_sqrt(int_sqrt(run_time)); if (s) points /= s;

長期運行、高 CPU 佔用的進程分數降低,受保護。

Nice 值影響

if (task_nice(p) > 0) points *= 2;

低優先級(nice 為正)進程分數翻倍,更易被殺。

Root 權限與硬體訪問保護

if (capable(CAP_SYS_ADMIN) || uid == 0) points /= 4;
if (capable(CAP_SYS_RAWIO)) points /= 4;

Root 進程、可訪問裸設備的進程分數降低 4 倍。

關鍵參數:oom_score_adj(舊版 oom_adj)

if (p->oom_score_adj > 0) points <<= p->oom_score_adj;
else points >>= -(p->oom_score_adj);

範圍 -1000 到 +1000(舊版 -17 到 +15),移位運算影響極大。設置 -1000 可實質免疫 OOM Killer。

實驗驗證

編寫測試程式申請 1GB 虛擬記憶體,每 10 秒實際佔用 +100MB。在 2GB 記憶體 + 400MB Swap 機器運行 3 個實例:

  • 默認 oom_score_adj=0 時,佔用最多、運行最短的進程被殺
  • 設置某進程 oom_adj=15 後,該進程優先被殺(分數左移 15 位,增長 32768 倍)

三個測試進程記憶體增長 Swap 空間減少 進程被 OOM Killer 終止 設置 oom_adj=15 被設置高優先級的進程被殺

為什麼不直接禁用 Overcommit?

設置 overcommit_memory=2 禁用過量分配雖能根治,但會導致:

  • MySQL 啟動時需預留所有配置記憶體,極大限制 Buffer Pool 設定
  • 動態分配(連接緩衝、排序、臨時表)失敗直接導致 Crash
  • 記憶體利用率大幅下降(預留未用無法共享)

Linux 設計 Overcommit 正是為平衡靈活性與風險。

結論

MySQL 通常是系統最大記憶體消費者,默認極易成 OOM Killer 目標。下章將從 MySQL 角度分析如何規避風險。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved