iftop 跑滿 CPU
故事的開始
某天一位系統大佬忙不過來了,拜託另一位大佬丟了個在 NC 上抓的 dump 讓我幫忙看下,現象很簡單,執行 iftop 時要過好幾分鐘才返回,同時 CPU 跑滿。
故事的進展
拿到 dump 先把對應的符號裝上去,然後用 crash 跑起來,先看看輸出了什麼。

除了能看到 iftop 正在執行之外,好像也沒什麼有用的資訊。
既然當前執行的程序剛好是 iftop,順便看下呼叫棧

看到這麼長的呼叫棧,一般都是有故事的。這個程序在執行某個動作的時候觸發了缺頁異常,然後在嘗試回收記憶體頁。
在 Linux 的記憶體管理中,有一個核心程序 kswapd 會在特定情況下默默回收最近最少使用(LRU)的記憶體頁,它回收的機制是這樣的:當空閒的記憶體頁低於 page_low 時,核心就會喚醒該程序,然後它會從 LRU 的記憶體頁中回收程序直到記憶體頁達到 page_high,由於存在 kswapd 主動回收記憶體的機制,一般來說,程序不會自己去做記憶體回收,只有在 kswapd 回收的記憶體也不能滿足程序的記憶體需求的時候程序才會自己去回收記憶體,出現這種現象有可能是 page_low 設定得太低了,導致喚醒 kswapd 的時候系統的空閒記憶體已經很少了,這種情況可以適當調大系統引數 vm.extra_free_kbytes。這裡多說一句,還有個引數是 pages_min,代表保留記憶體頁的數目,一般 pages_low 總是被設定為 pages_min 的 5/4,而 pages_high 總是被設定成 pages_min 的 3/2。而程序在自己回收記憶體的時候,做的動作時 direct reclaim,direct reclaim 的機制是不會區分 dirty 的記憶體頁和 clean 的記憶體頁,如果遇到 dirty 的記憶體頁會先把該記憶體頁寫回磁碟上再回收,因此,direct reclaim 比較消耗效能。
如果是這種情況,這個時候系統空閒的記憶體應該很少了,然鵝...

可以看到空閒記憶體還有一半以上,那就說明不是這個問題啊。
繼續查詢翻閱各種資料後,發現有個引數 vm.zone_reclaim_mode 控制著程序是否會在其它的 Zone 裡回收記憶體,當這個引數非 0 時,即使別的 Zone 裡有很多空閒記憶體,程序寧願自己回收記憶體也不會到別的 Zone 中去申請記憶體。如果是這種情況,確實會出現 free 的記憶體還很多但是程序還會自己去做 direct reclaim 來回收記憶體的情況。會不會是這個引數的問題呢?改完之後效果立竿見影,iftop 很快就能返回且不再跑滿 CPU 了!