內存回收
內存資源緊張會導致內存回收和 OOM 殺死進程。
內存回收,也就是系統釋放掉可以回收的內存,比如緩存和緩沖區,就屬於可回收內存。它們在內存管理中,通常被叫做文件頁(File-backed Page)。
大部分文件頁,都可以直接回收,以后有需要時,再從磁盤重新讀取就可以了。而那些被應用程序修改過,並且暫時還沒寫入磁盤的數據(也就是臟頁),就得先寫入磁盤,然后才能進行內存釋放。
除了文件頁,應用程序動態分配的堆內存,也就是我們在內存管理中說到的匿名頁(Anonymous Page)也可以被回收。(使用 Swap 回收)
Swap 機制
Swap 把這些不常訪問的內存先寫到磁盤中,然后釋放這些內存,給其他更需要的進程使用。再次訪問這些內存時,重新從磁盤讀入內存就可以了。
Swap 說白了就是把一塊磁盤空間或者一個本地文件(以下講解以磁盤為例),當成內存來使用。它包括換出和換入兩個過程。
- 所謂換出,就是把進程暫時不用的內存數據存儲到磁盤中,並釋放這些數據占用的內存。
- 而換入,則是在進程再次訪問這些內存的時候,把它們從磁盤讀到內存中來。
我們常見的筆記本電腦的休眠和快速開機的功能,也基於 Swap 。休眠時,把系統的內存存入磁盤,這樣等到再次開機時,只要從磁盤中加載內存就可以。這樣就省去了很多應用程序的初始化過程,加快了開機速度。
kswapd0
一個專門的內核線程用來定期回收內存,也就是 kswapd0。為了衡量內存的使用情況,kswapd0 定義了三個內存閾值(watermark,也稱為水位),分別是:
頁最小閾值(pages_min)、頁低閾值(pages_low)和頁高閾值(pages_high)。剩余內存,則使用 pages_free 表示。
- 剩余內存小於頁最小閾值,說明進程可用內存都耗盡了,只有內核才可以分配內存。
- 剩余內存落在頁最小閾值和頁低閾值中間,說明內存壓力比較大,剩余內存不多了。這時 kswapd0 會執行內存回收,直到剩余內存大於高閾值為止。
- 剩余內存落在頁低閾值和頁高閾值中間,說明內存有一定壓力,但還可以滿足新內存請求。
- 剩余內存大於頁高閾值,說明剩余內存比較多,沒有內存壓力。
swappiness
回收的內存既包括了文件頁,又包括了匿名頁。
- 對文件頁的回收,當然就是直接回收緩存,或者把臟頁寫回磁盤后再回收。
- 而對匿名頁的回收,其實就是通過 Swap 機制,把它們寫入磁盤后再釋放內存。
Linux 提供了一個 /proc/sys/vm/swappiness 選項,用來調整使用 Swap 的積極程度。
swappiness 的范圍是 0-100,數值越大,越積極使用 Swap,也就是更傾向於回收匿名頁;數值越小,越消極使用 Swap,也就是更傾向於回收文件頁。
總結
在內存資源緊張時,Linux 通過直接內存回收和定期掃描的方式,來釋放文件頁和匿名頁,以便把內存分配給更需要的進程使用。
- 文件頁的回收比較容易理解,直接清空,或者把臟數據寫回磁盤后再釋放。
- 而對匿名頁的回收,需要通過 Swap 換出到磁盤中,下次訪問時,再從磁盤換入到內存中。
你可以設置 /proc/sys/vm/min_free_kbytes,來調整系統定期回收內存的閾值(也就是頁低閾值),還可以設置 /proc/sys/vm/swappiness,來調整文件頁和匿名頁的回收傾向。
在 NUMA 架構下,每個 Node 都有自己的本地內存空間,而當本地內存不足時,默認既可以從其他 Node 尋找空閑內存,也可以從本地內存回收。
你可以設置 /proc/sys/vm/zone_reclaim_mode ,來調整 NUMA 本地內存的回收策略。
why Kubernetes 關閉 swap ?
- 一個是性能問題,開啟swap會嚴重影響性能(包括內存和I/O);
- 另一個是管理問題,開啟swap后通過cgroups設置的內存上限就會失效。
學習筆記
整理自極客時間:《Linux性能優化實戰》