swap用來(lái)做什么
緩存和緩沖區(qū)屬于可回收內(nèi)存,它們?cè)趦?nèi)存管理中,通常被叫做文件頁(yè)(File- backed page)大部分文件頁(yè)都可以直接回收,以后需要時(shí),再?gòu)拇疟P重新讀取就可以了,那些被應(yīng)用程序修改過(guò),并且暫時(shí)沒(méi)有寫入磁盤的數(shù)據(jù)(臟頁(yè))就得先寫入磁盤,然后才能進(jìn)行內(nèi)存釋放
除了文件頁(yè)外,應(yīng)用程序動(dòng)態(tài)分配的堆內(nèi)存叫做匿名頁(yè)(Anonymous Page)如堆,棧,數(shù)據(jù)段等,不是以文件形式存在,因此無(wú)法和磁盤文件交換,是通過(guò)swap機(jī)制把不常訪問(wèn)匿名頁(yè)占用的內(nèi)存寫入到磁盤中,然后釋放這些內(nèi)存,再次方式這些內(nèi)存時(shí),重新沖磁盤寫入內(nèi)存就可以了
匿名頁(yè) 和 文件頁(yè) 的回收都是基于LRU算法,優(yōu)先回收不常訪問(wèn)的內(nèi)存,所以LRU維護(hù)了active和inactive兩個(gè)雙向鏈表
- active:記錄活躍內(nèi)存頁(yè)
- inactive:記錄不活躍內(nèi)存頁(yè)
活躍和非活躍的 匿名頁(yè) 和 文件頁(yè) 大小查看
cat /proc/meminfo | grep -i active | sort
Active: 274616 kB
Active(anon): 38224 kB
Active(file): 236392 kB
Inactive: 320624 kB
Inactive(anon): 136 kB
Inactive(file): 320488 kB
swap 原理
Swap就是把一塊磁盤空間或者本地文件想做內(nèi)存來(lái)使用,它包括換出和換入兩個(gè)過(guò)程
- 換出:就是把進(jìn)程暫時(shí)不用的內(nèi)存數(shù)據(jù)存儲(chǔ)到磁盤中,并且釋放這些數(shù)據(jù)占用的內(nèi)存
- 換入:進(jìn)程再次訪問(wèn)這些內(nèi)存的時(shí)候,把它們從磁盤讀取到內(nèi)存中
使用場(chǎng)景
Swap其實(shí)就是把系統(tǒng)的可用內(nèi)存變大了,即使服務(wù)器內(nèi)存不足,頁(yè)可用運(yùn)行大內(nèi)存的應(yīng)用程序
- 內(nèi)存不足時(shí),有些程序并不想被OOM殺死,而是希望能緩一段時(shí)間,等待人工介入或者等系統(tǒng)自動(dòng)釋放其他進(jìn)程的內(nèi)容,再分配給它就會(huì)用到swap
swap也是為了回收匿名頁(yè)占用的內(nèi)存
直接內(nèi)存回收:當(dāng)有大塊內(nèi)存分配請(qǐng)求,但是內(nèi)存不足,這時(shí)候系統(tǒng)就會(huì)回收一部分內(nèi)存(比如緩存)盡可能的滿足新內(nèi)存的請(qǐng)求,這個(gè)過(guò)程叫做 直接內(nèi)存回收
定時(shí)內(nèi)存回收:內(nèi)核kswapd0線程用來(lái)定時(shí)回收內(nèi)存,為了衡量?jī)?nèi)存的使用情況,kswapd0定義了三個(gè)內(nèi)存閾值是 頁(yè)最小閾值(pages_min),頁(yè)低閾值(pages_low)和頁(yè)高閾值(pages_high),剩余內(nèi)存則使用pages_free表示

- 剩余內(nèi)存 < 頁(yè)最小閾值:說(shuō)明內(nèi)存可用內(nèi)存都耗盡了,只有內(nèi)核才可以分配內(nèi)存
- 剩余內(nèi)存落在頁(yè)最小閾值和頁(yè)低閾值中間:說(shuō)明內(nèi)存使用比較大,剩余內(nèi)存不多了,kswapd0回執(zhí)行內(nèi)存回收,知道剩余內(nèi)存大于高閾值為止
- 剩余內(nèi)存落在頁(yè)低閾值和頁(yè)高閾值中間:說(shuō)明內(nèi)存有一定壓力,但是還可以滿足新內(nèi)存請(qǐng)求。
- 剩余內(nèi)存 > 頁(yè)高閾值:說(shuō)明剩余內(nèi)存比較對(duì),沒(méi)有內(nèi)存壓力
頁(yè)低賦值可以通過(guò)內(nèi)核選項(xiàng)vm.min_free_kbytes 間接設(shè)置 /proc/sys/vm/min_free_kbytes,min_free_kbytes設(shè)置了頁(yè)最小閾值,其他兩個(gè)閾值根據(jù)頁(yè)最小閾值計(jì)算生成的
pages_low = pages_min*5/4
pages_high = pages_min*3/2
NUMA與Swap
有時(shí)候系統(tǒng)內(nèi)存剩余還很多,但是Swap還是升高了,是因?yàn)樘幚砥鱊UMA架構(gòu)導(dǎo)致的
在NUMA框架下,多個(gè)處理器被劃分到不同Node上,且每個(gè)Node 都擁有自己的本地內(nèi)存空間,并且進(jìn)一步又分為內(nèi)內(nèi)參域(zone),不如 直接內(nèi)存訪問(wèn)區(qū)(DMA),普通內(nèi)存區(qū)(NORMAL),偽內(nèi)存區(qū)(MOVABLE)等
因?yàn)镹UMA框架下每個(gè)Node都有自己的本地內(nèi)存空間,所以分析內(nèi)存使用需要根據(jù)每個(gè)Node單獨(dú)分析, 可以通過(guò)numactl 查看每個(gè)Node內(nèi)存使用情況
[root@master1 ~]# numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3
node 0 size: 8191 MB
node 0 free: 1793 MB
node distances:
node 0
0: 10
根據(jù)這個(gè)輸出,我們系統(tǒng)中只有一個(gè)Node,就是Node0,編號(hào)為0 1 2 3的CPU都位于Node0上。另外Node0的內(nèi)存大小為 8191 MB,剩余1793 MB
前面提到的頁(yè)最小,頁(yè)低,頁(yè)高的三個(gè)閾值都可以在內(nèi)存域/proc/zoneinfo來(lái)查看
[root@master1 ~]# cat /proc/zoneinfo | grep -i -A 15 "Node 0"
Node 0, zone DMA
pages free 3975
min 30
low 37
high 45
scanned 0
spanned 4095
present 3998
managed 3977
nr_free_pages 3975
nr_alloc_batch 8
nr_inactive_anon 0
nr_active_anon 0
nr_inactive_file 0
nr_active_file 0
nr_unevictable 0
--
Node 0, zone DMA32
pages free 159434
min 5530
low 6912
high 8295
scanned 0
spanned 1044480
present 782327
managed 721081
nr_free_pages 159434
nr_alloc_batch 1343
nr_inactive_anon 14605
nr_active_anon 95179
nr_inactive_file 193717
nr_active_file 206850
nr_unevictable 0
--
Node 0, zone Normal
pages free 295068
min 9798
low 12247
high 14697
scanned 0
spanned 1310720
present 1310720
managed 1277513
nr_free_pages 295068
nr_alloc_batch 127
nr_inactive_anon 16505
nr_active_anon 141332
nr_inactive_file 335925
nr_active_file 383442
nr_unevictable 0
上面輸出包含了三個(gè)內(nèi)存域的指標(biāo),min,low,high 就是上面提到的三個(gè)內(nèi)存閾值,而free是剩余內(nèi)存頁(yè)數(shù)它跟后面的nr_free_pages相同 注意: 這里單位是頁(yè),每一頁(yè)是4kb,比如計(jì)算頁(yè)最小閾值需要把 三個(gè)zone的min相加 * 4kb(9798 + 5530 + 30)* 4
根據(jù)輸入內(nèi)容發(fā)現(xiàn)pages free剩余內(nèi)存遠(yuǎn)高于high,所以此時(shí)kswapd0不會(huì)回收內(nèi)存,當(dāng)某個(gè)Node內(nèi)存不足時(shí),系統(tǒng)可以從其他Node尋找空閑內(nèi)容,頁(yè)可以從本地內(nèi)存中回收內(nèi)存,需要選哪個(gè)模式,可以通過(guò)/proc/sys/vm/zone_reclaim_mode來(lái)調(diào)整
- 默認(rèn)為0,也就是剛剛提到的模式,表示既可以從其他Node尋找空閑內(nèi),頁(yè)可以從本地回收內(nèi)存,這時(shí)候就會(huì)導(dǎo)致回收文件頁(yè)和匿名頁(yè),匿名頁(yè)的回收所以會(huì)觸發(fā)swap
- 1,2,4,表示只回收本地內(nèi)存,2表示可以回收寫臟數(shù)據(jù)回收內(nèi)存,4表示可以用Swap方式回收內(nèi)存
swappiness
使用swap的積極程度可以通過(guò)內(nèi)核參數(shù) vm.swappiness 間接配置 /proc/sys/vm/swappiness 選項(xiàng),配置范圍0-100,數(shù)字越大,越積極使用Swap,也就是更傾向于回收匿名頁(yè),數(shù)值越小,越消極使用Swap
即使你設(shè)置為0,當(dāng)剩余內(nèi)存文件頁(yè)小于高閾值時(shí),還是會(huì)發(fā)生Swap
# 按VmSwap使用量對(duì)進(jìn)程排序,輸出進(jìn)程名稱、進(jìn)程ID以及SWAP用量
$ for file in /proc/*/status ; do awk '/VmSwap|Name|^Pid/{printf $2 " " $3}END{ print ""}' $file; done | sort -k 3 -n -r | head
dockerd 2226 10728 kB
docker-containe 2251 8516 kB
snapd 936 4020 kB
networkd-dispat 911 836 kB
polkitd 1004 44 kB
總結(jié)
Linux通過(guò)直接內(nèi)存回收和定時(shí)內(nèi)存掃描回收方式來(lái)釋放文件頁(yè)和匿名頁(yè)
- 文件頁(yè)的回收:就是直接回收緩存,或者把臟數(shù)據(jù)寫回磁盤后釋放
- 匿名也的回收:需要通過(guò)Swap換出到磁盤中,下次訪問(wèn)時(shí),在從磁盤換入到內(nèi)存中
定時(shí)內(nèi)存掃描回收方式的閾值可以通過(guò)內(nèi)核選項(xiàng)vm.min_free_kbytes來(lái)設(shè)置
只要涉及到回收匿名頁(yè)就會(huì)涉及觸發(fā)Swap
假如沒(méi)有開啟swap的話,進(jìn)程的匿名頁(yè)就無(wú)法釋放,需要在進(jìn)程的重啟或者殺掉釋放
swap使用積極程度可以通過(guò)內(nèi)核參數(shù)vm.swappiness 設(shè)置
在處理器NUMA框架下,每個(gè)Node都有自己的內(nèi)存域,某個(gè)Node自己內(nèi)存域下剩余內(nèi)存不多情況下,導(dǎo)致內(nèi)存回收也就有可能觸發(fā)Swap