LWN:儘快釋放被殺死的程序記憶體
Expedited memory reclaim from killed processes
By Jonathan Corbet, April 12, 2019
https://lwn.net/Articles/785709/
Linux執行時如果記憶體不足了會很難處理,最壞情況下沒有其他方法能緩解,只得開始kill程序來回收記憶體。kill程序的動作可能是kernel自己來進行,也可能是由使用者系統(例如Android)通過在user-space實現一個out-of-memory(OOM)的監控程序來kill。可以肯定的是被kill的程序肯定不爽,那麼kernel應該儘量快地回收這個程序的記憶體空間,試圖避免繼續kill別的程序。可是目前kernel裡面行為,有時候並不是這樣的。
Suren Baghdasaryan提交的一組patch就是希望能改善這個現象。不過目前這組patch爭議頗多,最終解決方案可能會完全是另一個樣子。Kernel裡面要求每個程序在exit的時候清理他們自己的資源。因此在某個程序被OOM killer殺死後,它需要先在kernel裡面得到執行的機會來釋放它所佔用的memory resource給記憶體管理系統。如果這個程序的優先順序太低,或者它一直在等待系統裡的其他什麼資源,那麼就會花費很長時間才能完成清理工作。與此同時,系統因為沒有得到原本應該釋放出來的memory,所以仍然資源非常緊張,很快就會去kill第二個程序來繼續釋放它的記憶體。
2015年就有OOM reaper方案被提出來,希望解決這個問題。當kernel的OOM killer準備kill一個程序的時候,它會盡快把這個程序的記憶體剝奪掉,不允許它再訪問。不過OOM reaper方案無法讓user-space的OOM killer程序來呼叫。那些user-space的OOM killer只能傳送SIGKILL signal來通知目標程序儘快退出,然後就聽天由命了,它才搞不清楚被kill的程序會花費多長時間才能真正退出以及釋放資源。Baghdasaryan指出,這裡帶來的負面影響就是user space必須要預留一個比較大的free pages,並且要提前開始kill程序。
Baghdasaryan的方案是為Linux 5.1裡面引入的pidfd_send_signal()增加了一個flag:SS_EXPEDITE。呼叫時如果提供了這個flag,就說明呼叫者有CAP_SYS_NICE的能力並且傳送的signal就是SIGKILL,然後OOM reaper就可以儘快剝奪被kill程序的資源。如此一來user space的OOM killer也能儘快kill某個程序及釋放資源了,不用擔心會不會目標程序被什麼其他事情給拖慢了。
有趣的是雖然大多數人都贊同這個目標,但是review comments整體卻都是各種異議。最主要的反對意見來自Michal Hocko(OOM reaper的作者),他抱怨說:“這個方案是濫用了OOM的的一個行為,把它變成了一個正式的API”。他還在問,這個能力是否真的有用,因為依賴清理的速度是“一個基本的設計問題”。Johannes Weiner卻針對這個觀點提出不同看法:“就要讓使用者體驗優化到最好”。其他人基本都同意在程序退出的時候應該快速釋放記憶體。
Daniel Colascione挺喜歡這個注意,不過想要改一下這個介面(interface),他覺得不應該繫結到某個signal,而是增加一個新的system call(系統呼叫),類似這樣:
size_t try_reap_dying_process(int pidfd, int flags, size_t max_bytes);
呼叫這個系統呼叫就會剝奪pidfd所指向的程序的記憶體(這個動作只在程序退出的時候才發生)。max_bytes這個引數用來告訴kernel,發起系統呼叫的人(user-space OOM killer)希望能拿到多少記憶體。這樣kernel就不用把被kill程序的所有記憶體都剝奪掉了,只需要達到max_bytes數量即可。需要注意的是,剝奪記憶體的動作是發生在發起系統呼叫的程序空間裡,這樣user space就能根據當前程序的重要性來決定kill和釋放的記憶體數量細節。
Matthew Wilcox提出一個簡單的問題:為什麼不在程序退出的時候直接儘快回收記憶體,而要等這個特殊的系統呼叫才做這件事?Weiner同意他的觀點,既然釋放記憶體總是要做的,乾脆每次都馬上處理掉即可,不用那麼麻煩再去呼叫一個系統呼叫。不過Daniel Colascione指出這個機制會減慢SIGKILL的處理流程,例如killall執行的時候就可能觀察到變慢了。
Baghdasaryan也不覺得“每次”剝奪記憶體都儘快完成是一個合理的需求。不過,確實在有些時候這個是非常必要的:“如果我們能不依賴user space的引數和提示就瞭解到哪次操作是緊急的,哪次操作不是,那就太好了。所以我很歡迎大家提出一些方案能不依賴一個新的flag”。如果能找到這樣的一個方案,最終估計會得到大家的贊同從而合併入Linux kernel。無論如何,清理一個被kill的程序的工作,都是kernel的責任。大家不太會喜歡建立一個新的interface來把這個責任轉移給user space,最好還是能找到一個不依賴新的API的方案,讓我們拭目以待吧。
全文完
極度歡迎將文章分享到朋友圈
長按下面二維碼關注:Linux News搬運工,希望每週的深度文章以及開源社群的各種新近言論,能夠讓大家滿意~