19 | 案例篇:为什么系统的Swap变高了(上)
生活随笔
收集整理的這篇文章主要介紹了
19 | 案例篇:为什么系统的Swap变高了(上)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
上一節(jié),我通過一個斐波那契數(shù)列的案例,帶你學習了內(nèi)存泄漏的分析。如果在程序中直接或間接地分配了動態(tài)內(nèi)存,你一定要記得釋放掉它們,否則就會導致內(nèi)存泄漏,嚴重時甚至會耗盡系統(tǒng)內(nèi)存。不過,反過來講,當發(fā)生了內(nèi)存泄漏時,或者運行了大內(nèi)存的應用程序,導致系統(tǒng)的內(nèi)存資源緊張時,系統(tǒng)又會如何應對呢?在內(nèi)存基礎篇我們已經(jīng)學過,這其實會導致兩種可能結果,內(nèi)存回收和 OOM 殺死進程。我們先來看后一個可能結果,內(nèi)存資源緊張導致的 OOM(Out Of Memory),相對容易理解,指的是系統(tǒng)殺死占用大量內(nèi)存的進程,釋放這些內(nèi)存,再分配給其他更需要的進程。這一點我們前面詳細講過,這里就不再重復了。接下來再看第一個可能的結果,內(nèi)存回收,也就是系統(tǒng)釋放掉可以回收的內(nèi)存,比如我前面講過的緩存和緩沖區(qū),就屬于可回收內(nèi)存。它們在內(nèi)存管理中,通常被叫做文件頁(File-backed Page)。大部分文件頁,都可以直接回收,以后有需要時,再從磁盤重新讀取就可以了。而那些被應用程序修改過,并且暫時還沒寫入磁盤的數(shù)據(jù)(也就是臟頁),就得先寫入磁盤,然后才能進行內(nèi)存釋放。這些臟頁,一般可以通過兩種方式寫入磁盤。
- 可以在應用程序中,通過系統(tǒng)調(diào)用 fsync ,把臟頁同步到磁盤中;
- 也可以交給系統(tǒng),由內(nèi)核線程 pdflush 負責這些臟頁的刷新。
文件頁
除了緩存和緩沖區(qū),通過內(nèi)存映射獲取的文件映射頁,也是一種常見的文件頁。它也可以被釋放掉,下次再訪問的時候,從文件重新讀取。匿名頁
除了文件頁外,還有沒有其他的內(nèi)存可以回收呢?比如,應用程序動態(tài)分配的堆內(nèi)存,也就是我們在內(nèi)存管理中說到的匿名頁(Anonymous Page),是不是也可以回收呢?我想,你肯定會說,它們很可能還要再次被訪問啊,當然不能直接回收了。非常正確,這些內(nèi)存自然不能直接釋放。但是,如果這些內(nèi)存在分配后很少被訪問,似乎也是一種資源浪費。是不是可以把它們暫時先存在磁盤里,釋放內(nèi)存給其他更需要的進程?其實,這正是 Linux 的 Swap 機制。Swap 把這些不常訪問的內(nèi)存先寫到磁盤中,然后釋放這些內(nèi)存,給其他更需要的進程使用。再次訪問這些內(nèi)存時,重新從磁盤讀入內(nèi)存就可以了。在前幾節(jié)的案例中,我們已經(jīng)分別學過緩存和 OOM 的原理和分析。那 Swap 又是怎么工作的呢?因為內(nèi)容比較多,接下來,我將用兩節(jié)課的內(nèi)容,帶你探索 Swap 的工作原理,以及 Swap 升高后的分析方法。今天我們先來看看,Swap 究竟是怎么工作的。Swap 原理
前面提到,Swap 說白了就是把一塊磁盤空間或者一個本地文件(以下講解以磁盤為例),當成內(nèi)存來使用。它包括換出和換入兩個過程。- 所謂換出,就是把進程暫時不用的內(nèi)存數(shù)據(jù)存儲到磁盤中,并釋放這些數(shù)據(jù)占用的內(nèi)存。
- 而換入,則是在進程再次訪問這些內(nèi)存的時候,把它們從磁盤讀到內(nèi)存中來。
- 剩余內(nèi)存小于頁最小閾值,說明進程可用內(nèi)存都耗盡了,只有內(nèi)核才可以分配內(nèi)存。
- 剩余內(nèi)存落在頁最小閾值和頁低閾值中間,說明內(nèi)存壓力比較大,剩余內(nèi)存不多了。這時 kswapd0 會執(zhí)行內(nèi)存回收,直到剩余內(nèi)存大于高閾值為止。
- 剩余內(nèi)存落在頁低閾值和頁高閾值中間,說明內(nèi)存有一定壓力,但還可以滿足新內(nèi)存請求。
- 剩余內(nèi)存大于頁高閾值,說明剩余內(nèi)存比較多,沒有內(nèi)存壓力。
NUMA 與 Swap
很多情況下,你明明發(fā)現(xiàn)了 Swap 升高,可是在分析系統(tǒng)的內(nèi)存使用時,卻很可能發(fā)現(xiàn),系統(tǒng)剩余內(nèi)存還多著呢。為什么剩余內(nèi)存很多的情況下,也會發(fā)生 Swap 呢?看到上面的標題,你應該已經(jīng)想到了,這正是處理器的 NUMA (Non-Uniform Memory Access)架構導致的。關于 NUMA,我在 CPU 模塊中曾簡單提到過。在 NUMA 架構下,多個處理器被劃分到不同 Node 上,且每個 Node 都擁有自己的本地內(nèi)存空間。而同一個 Node 內(nèi)部的內(nèi)存空間,實際上又可以進一步分為不同的內(nèi)存域(Zone),比如直接內(nèi)存訪問區(qū)(DMA)、普通內(nèi)存區(qū)(NORMAL)、偽內(nèi)存區(qū)(MOVABLE)等,如下圖所示:先不用特別關注這些內(nèi)存域的具體含義,我們只要會查看閾值的配置,以及緩存、匿名頁的實際使用情況就夠了。既然 NUMA 架構下的每個 Node 都有自己的本地內(nèi)存空間,那么,在分析內(nèi)存的使用時,我們也應該針對每個 Node 單獨分析。你可以通過 numactl 命令,來查看處理器在 Node 的分布情況,以及每個 Node 的內(nèi)存使用情況。比如,下面就是一個 numactl 輸出的示例:$ numactl --hardware available: 1 nodes (0) node 0 cpus: 0 1 node 0 size: 7977 MB node 0 free: 4416 MB ...這個界面顯示,我的系統(tǒng)中只有一個 Node,也就是 Node 0 ,而且編號為 0 和 1 的兩個 CPU, 都位于 Node 0 上。另外,Node 0 的內(nèi)存大小為 7977 MB,剩余內(nèi)存為 4416 MB。了解了 NUNA 的架構和 NUMA 內(nèi)存的查看方法后,你可能就要問了這跟 Swap 有什么關系呢?實際上,前面提到的三個內(nèi)存閾值(頁最小閾值、頁低閾值和頁高閾值),都可以通過內(nèi)存域在 proc 文件系統(tǒng)中的接口 /proc/zoneinfo 來查看。比如,下面就是一個 /proc/zoneinfo 文件的內(nèi)容示例:$ cat /proc/zoneinfo ... Node 0, zone Normalpages free 227894min 14896low 18620high 22344 ...nr_free_pages 227894nr_zone_inactive_anon 11082nr_zone_active_anon 14024nr_zone_inactive_file 539024nr_zone_active_file 923986 ...這個輸出中有大量指標,我來解釋一下比較重要的幾個。- pages 處的 min、low、high,就是上面提到的三個內(nèi)存閾值,而 free 是剩余內(nèi)存頁數(shù),它跟后面的 nr_free_pages 相同。
- nr_zone_active_anon 和 nr_zone_inactive_anon,分別是活躍和非活躍的匿名頁數(shù)。
- nr_zone_active_file 和 nr_zone_inactive_file,分別是活躍和非活躍的文件頁數(shù)。
- 默認的 0 ,也就是剛剛提到的模式,表示既可以從其他 Node 尋找空閑內(nèi)存,也可以從本地回收內(nèi)存。
- 1、2、4 都表示只回收本地內(nèi)存,2 表示可以回寫臟數(shù)據(jù)回收內(nèi)存,4 表示可以用 Swap 方式回收內(nèi)存。
swappiness
到這里,我們就可以理解內(nèi)存回收的機制了。這些回收的內(nèi)存既包括了文件頁,又包括了匿名頁。- 對文件頁的回收,當然就是直接回收緩存,或者把臟頁寫回磁盤后再回收。
- 而對匿名頁的回收,其實就是通過 Swap 機制,把它們寫入磁盤后再釋放內(nèi)存。
小結
在內(nèi)存資源緊張時,Linux 通過直接內(nèi)存回收和定期掃描的方式,來釋放文件頁和匿名頁,以便把內(nèi)存分配給更需要的進程使用。- 文件頁的回收比較容易理解,直接清空,或者把臟數(shù)據(jù)寫回磁盤后再釋放。
- 而對匿名頁的回收,需要通過 Swap 換出到磁盤中,下次訪問時,再從磁盤換入到內(nèi)存中。
總結
以上是生活随笔為你收集整理的19 | 案例篇:为什么系统的Swap变高了(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 18 | 案例篇:内存泄漏了,我该如何定
- 下一篇: Redis 实战笔记