oom-killer 在 Linux 用戶中通常名聲不佳。這可能是 Linux 僅在別無選擇時才調用它的部分原因。它將交換桌面環境,刪除整個頁面快取並清空每個緩衝區,然後最終殺死進程。至少我認為它會做到這一點。我還沒有足夠的耐心等待它,坐在一個沒有反應的系統前面。
這讓我和其他人想知道 oom-killer 是否可以配置為更早介入:reddit r/linux、superuser.com、unix.stackexchange.com。
事實證明,不,不能。至少使用核心中的 oom-killer。然而,在使用者空間,我們可以做任何我們想做的事情。
Earlyoom 希望簡單可靠。它是用純 C 語言編寫的,沒有依賴關係。廣泛的測試套件(單元測試和整合測試)是用 Go 編寫的。
Earlyoom 每秒最多檢查 10 次可用內存和可用交換空間(如果有大量可用內存,則頻率會降低)。預設情況下,如果兩者都低於 10%,它將殺死最大的進程(最高的oom_score
)。百分比值可透過命令列參數進行設定。
在下面的free -m
輸出中,可用記憶體為 2170 MiB,可用交換空間為 231 MiB。
total used free shared buff/cache available Mem: 7842 4523 137 841 3182 2170 Swap: 1023 792 231
為什麼檢查“可用”內存而不是“空閒”內存?在一個健康的 Linux 系統上,「空閒」記憶體應該接近零,因為 Linux 使用所有可用的實體記憶體來快取磁碟存取。當記憶體需要用於其他用途時,可以隨時刪除這些快取。
「可用」記憶體說明了這一點。它匯總了所有未使用或可以立即釋放的記憶體。
請注意,您需要最新版本的free
版本和 Linux 核心 3.14+ 才能看到「可用」列。如果您有最新的內核,但free
版本較舊,則可以從grep MemAvailable /proc/meminfo
取得值。
當你的可用記憶體和空閒交換區都低於用戶空間進程可用總記憶體(=total-shared)的 10% 時,它將向核心認為使用最多記憶體的進程發送SIGTERM
訊號( /proc/*/oom_score
) 。
nohang,一個類似 Earlyoom 的項目,用 Python 編寫,並具有附加功能和配置選項。
facebooks 的壓力失速資訊 (psi) 核心修補程式和隨附的 oomd 用戶空間幫助程式。這些補丁已合併到 Linux 4.20 中。
Earlyoom 不使用echo f > /proc/sysrq-trigger
因為:
在某些核心版本中(在 v4.0.5 上測試),手動觸發核心 oom Killer 根本不起作用。也就是說,它可能只會釋放一些圖形記憶體(將立即再次分配),而不會真正殺死任何進程。在這裡您可以看到它在我的機器(英特爾整合式顯示卡)上的樣子。
此問題已在 Linux v5.17 中修復(提交 f530243a)。
就像 Linux 核心一樣,earlyoom 透過讀取/proc/*/oom_score
來找到它的受害者。
大約2 MiB
( VmRSS
),儘管只有220 kiB
是私有記憶體 ( RssAnon
)。其餘的則是與其他行程共用的 libc 函式庫 ( RssFile
)。使用mlockall()
鎖定所有內存,以確保 Earlyoom 在內存不足的情況下不會減慢速度。
自己編譯很容易:
git 克隆 https://github.com/rfjakob/earlyoom.gitcd Earlyoom 製作
可選:運行整合自測試:
進行測試
透過將earlyoom註冊為服務來自動啟動earlyoom:
sudo make install # systemdsudo make install-initscript # 非systemd
請注意,對於停用 SELinux 的系統(Ubuntu 19.04、Debian 9 ...),可以安全地忽略報告設定上下文失敗的 chcon 警告。
對於 Debian 10+ 和 Ubuntu 18.04+,有一個 Debian 軟體包:
sudo apt install Earlyoom
對於 EPEL 的 Fedora 和 RHEL 8,有一個 Fedora 軟體包:
須藤 dnf 安裝 Earlyoom sudo systemctl啟用--現在earlyoom
對於 Arch Linux,有一個 Arch Linux 軟體包:
sudo pacman -S Earlyoom sudo systemctl啟用--現在earlyoom
其他發行版中的可用性:請參閱repology 頁面。
只需啟動剛剛編譯的可執行檔:
./清晨
它會告訴您有多少記憶體和交換空間,最小值是多少,有多少記憶體可用以及有多少交換空間是可用的。
./earlyoom eearlyoom v1.8 mem total: 23890 MiB, user mem total: 21701 MiB, swap total: 8191 MiB sending SIGTERM when mem avail <= 10.00% and swap free <= 10.00%, SIGKILL when mem avail <= 5.00% and swap free <= 5.00% mem avail: 20012 of 21701 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%) mem avail: 20031 of 21721 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%) mem avail: 20033 of 21723 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%) [...]
如果該值低於最小值,則進程將終止,直到再次高於最小值。每個操作都會記錄到 stderr。如果您將 Earlyoom 作為 systemd 服務運行,則可以使用以下命令查看最後 10 行
systemctl狀態earlyoom
為了查看earlyoom
實際效果,請建立/模擬記憶體洩漏並讓earlyoom
執行其操作:
tail /dev/zero
如果您在進程被earlyoom
終止後需要任何進一步的操作(例如發送電子郵件),您可以透過以下方式解析日誌:
sudo journalctl -u earlyoom | grep sending
上述測試指令( tail /dev/zero
)的範例輸出將如下所示:
Feb 20 10:59:34 debian earlyoom[10231]: sending SIGTERM to process 7378 uid 1000 "tail": oom_score 156, VmRSS 4962 MiB
對於舊版的
earlyoom
,請使用:sudo journalctl -u earlyoom | grep -iE "(sending|killing)"
從 1.6 版本開始,earlyoom 可以透過系統 d-bus 發送有關終止進程的通知。通過-n
來啟用它們。
要實際在 GUI 會話中查看通知,您需要以使用者身分執行 systembus-notify。
此外,earlyoom 可以為每個被殺死的進程執行一個腳本,透過EARLYOOM_PID
、 EARLYOOM_UID
和EARLYOOM_NAME
環境變數提供有關進程的資訊。透過-N /path/to/script
來啟用。
警告:在 dryrun 模式下,腳本將快速連續執行,確保您實作了某種速率限制。
命令列標誌--prefer
指定優先殺死進程;同樣, --avoid
指定避免殺死的進程。有關詳細信息,請參閱 https://github.com/rfjakob/earlyoom/blob/master/MANPAGE.md#--prefer-regex。
如果您將 Earlyoom 作為系統服務運行(透過 systemd 或 init.d),則可以透過/etc/default/earlyoom
中提供的檔案調整其配置。該文件已在註釋中包含一些範例,您可以使用它們根據支援的命令列選項建立自己的配置集,例如:
EARLYOOM_ARGS="-m 5 -r 60 --avoid '(^|/)(init|Xorg|ssh)$' --prefer '(^|/)(java|chromium)$'"
調整文件後,只需重新啟動服務即可套用變更。例如,對於 systemd:
systemctl 重新啟動 Earlyoom
請注意,此設定檔對 systemd/init.d 以外的 Earlyoom 實例沒有影響。
earlyoom v1.8 Usage: ./earlyoom [OPTION]... -m PERCENT[,KILL_PERCENT] set available memory minimum to PERCENT of total (default 10 %). earlyoom sends SIGTERM once below PERCENT, then SIGKILL once below KILL_PERCENT (default PERCENT/2). -s PERCENT[,KILL_PERCENT] set free swap minimum to PERCENT of total (default 10 %). Note: both memory and swap must be below minimum for earlyoom to act. -M SIZE[,KILL_SIZE] set available memory minimum to SIZE KiB -S SIZE[,KILL_SIZE] set free swap minimum to SIZE KiB -n enable d-bus notifications -N /PATH/TO/SCRIPT call script after oom kill -g kill all processes within a process group -d, --debug enable debugging messages -v print version information and exit -r INTERVAL memory report interval in seconds (default 1), set to 0 to disable completely -p set niceness of earlyoom to -20 and oom_score_adj to -100 --ignore-root-user do not kill processes owned by root --sort-by-rss find process with the largest rss (default oom_score) --prefer REGEX prefer to kill processes matching REGEX --avoid REGEX avoid killing processes matching REGEX --ignore REGEX ignore processes matching REGEX --dryrun dry run (do not kill any processes) --syslog use syslog instead of std streams -h, --help this help text
有關詳細信息,請參閱手冊頁。
歡迎透過 github 提交錯誤報告和拉取請求。特別是我很高興接受
使用案例報告和回饋
我們不使用 procps/libproc2,因為 procps_pids_select() 因為某些原因總是解析 /proc/$pid/status。這個比較貴,我們不需要。
v1.8.2, 2024-05-07
將process_mrelease
加入到允許的系統呼叫(提交)
修復IPAddressDeny
語法(提交)
允許-p
(提交)
修復了earlyoom.service
systemd 單元文件
v1.8.1, 2024-04-17
修復因訊息改寫而導致的小測試失敗(提交)
v1.8, 2024-04-15
引入user mem total
/ meminfo_t.UserMemTotal
並根據它計算 MemAvailablePercent (提交,手冊頁中的更多資訊)
使用process_mrelease
(#266)
支援NO_COLOR
(https://no-color.org/)
不要對殭屍主執行緒的進程感到困惑(提交)
添加--sort-by-rss
,謝謝@RanHuang!這將選擇一個進程來殺死 acc。使用最大的 RSS 而不是最大的 oom_score。
Gitlab CI 測試套件現在也可以在 Amazon Linux 2 和 Oracle Linux 7 上運作。
v1.7, 2022-03-05
新增-N
標誌以在每次進程被終止時執行腳本(提交,手冊頁部分)
新增-g
標誌來終止整個進程組 (#247)
刪除-i
標誌(為了相容性而忽略),它在 Linux 核心 5.9+ 上無法正常運作(#234)
強化:啟動時刪除環境功能 (#234)
v1.6.2, 2020-10-14
在殺死受害者之前仔細檢查內存情況(提交)
永遠不要終止我們自己(#205)
/proc/meminfo 轉換錯誤時轉儲緩衝區 (#214)
1.6.1, 2020-07-07
清理 dbus-send 殭屍行程 (#200)
跳過 oom_score_adj=-1000 (210) 的進程
1.6, 2020-04-11
-n
/ -N
現在啟用新邏輯
您需要在 GUI 會話中執行 systembus-notify 以取得工作通知
用dbus-send
/ systembus-notify 取代舊的notify-send
GUI 通知邏輯 (#183)
優雅地處理使用 hidepid 掛載的/proc
(問題 #184)
v1.5, 2020-03-22
-p
: 將 oom_score_adj 設為-100
而不是-1000
(#170)
允許同時使用-M
和-m
以及-S
和-s
。將使用較低的值(轉換為百分比)。
將earlyoom.default
中的記憶體報告間隔設定為1小時而不是1分鐘(#177)
v1.4, 2020-03-01
盡可能使用區塊局部變數
引入 PATH_LEN 來取代幾個硬編碼的緩衝區長度
透過延遲載入進程屬性使受害者選擇邏輯速度提高 50%
除了 pid 和名稱之外,還記錄已終止進程的使用者 ID uid
顏色調試日誌為淺灰色
程式碼清理
展開測試套件( make test
)
可用時運行cppcheck
新增單元測試基準( make bench
)
刪除 systemd 單元檔案earlyoom.service
中的 root 權限
v1.3.1, 2020-02-27
修復具有大量 RAM 的系統上的虛假測試套件故障(問題 #156)
v1.3, 2019-05-26
如果 SIGTERM 限制 < SIGKILL 限制,則不要退出並出現致命錯誤
允許零 SIGKILL 限制
這解決了 Earlyoom 有時在一個進程就足夠時殺死多個進程的問題(問題#121)
發送訊號時等待進程實際退出
對 SIGTERM 和 SIGKILL 的接受限制更為自由(問題 #97)
重新格式化啟動輸出以明確 swap 和 mem 都必須 <= limit
新增notify_all_users.py幫助腳本
新增 CODE_OF_CONDUCT.md(貢獻者契約 1.4)(#102)
修正日誌輸出中可能被截斷的 UTF8 應用程式名稱 (#110)
v1.2, 2018-10-28
實施自適應睡眠時間(=自適應輪詢率)以進一步降低 CPU 使用率(問題 #61)
刪除使用內核 oom-killer 的選項( -k
,現在為了相容性而忽略)(問題#80)
優雅地處理 Earlyoom 啟動後新增或刪除交換的情況(第 62 期,提交)
實施分階段終止:首先是 SIGTERM,然後是 SIGKILL,並具有可設定的限制(問題 #67)
v1.1, 2018-07-07
透過 GUI 通知修復可能的 shell 程式碼注入(提交)
如果無法終止任何進程,則僅休眠 1 秒而不是 10 秒(問題 #74)
在殺死之後發送 GUI 通知,而不是之前(問題 #73)
除了-h
之外還接受--help
修正日誌和終止通知中錯誤的進程名稱(提交 1、提交 2、問題 #52、問題 #65、問題 #194)
使用-S
修復可能被零除的情況(提交)
v1.0, 2018-01-28
新增--prefer
和--avoid
選項 (@TomJohnZ)
新增對 GUI 通知的支持,新增選項-n
和-N
v0.12:新增-M
和-S
選項(@nailgun);新增手冊頁,參數化 Makefile (@yangfl)
v0.11:修正 get_entry_fatal 中未定義的行為(缺少回傳、提交)
v0.10:允許覆蓋Makefile的VERSION變數以使打包更容易,新增-v
命令列選項
v0.9:如果所有行程的oom_score為0,則使用VmRss找出受害者
v0.8:如果核心不提供 MemAvailable,則使用猜測
v0.7:透過 oom_score 而不是 VmRSS 選擇受害者,新增選項-i
和-d
v0.6: 新增命令列選項-m
, -s
, -k
v0.5:新增交換支持
v0.4:新增 SysV 初始化腳本(感謝 @joeytwiddle),使用/proc/meminfo
中的新MemAvailable
(需要 Linux 3.14+,提交)
v0.2:新增systemd單元文件
v0.1:初始版本