swap用來做什么
緩存和緩沖區(qū)屬于可回收內(nèi)存,它們在內(nèi)存管理中底哥,通常被叫做文件頁(File- backed page)大部分文件頁都可以直接回收,以后需要時,再從磁盤重新讀取就可以了烁涌,那些被應(yīng)用程序修改過,并且暫時沒有寫入磁盤的數(shù)據(jù)(臟頁)就得先寫入磁盤酒觅,然后才能進行內(nèi)存釋放
除了文件頁外撮执,應(yīng)用程序動態(tài)分配的堆內(nèi)存叫做匿名頁(Anonymous Page)如堆,棧舷丹,數(shù)據(jù)段等抒钱,不是以文件形式存在,因此無法和磁盤文件交換颜凯,是通過swap機制把不常訪問匿名頁占用的內(nèi)存寫入到磁盤中谋币,然后釋放這些內(nèi)存,再次方式這些內(nèi)存時症概,重新沖磁盤寫入內(nèi)存就可以了
匿名頁 和 文件頁 的回收都是基于LRU算法蕾额,優(yōu)先回收不常訪問的內(nèi)存,所以LRU維護了active和inactive兩個雙向鏈表
- active:記錄活躍內(nèi)存頁
- inactive:記錄不活躍內(nèi)存頁
活躍和非活躍的 匿名頁 和 文件頁 大小查看
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)存來使用彼城,它包括換出和換入兩個過程
- 換出:就是把進程暫時不用的內(nèi)存數(shù)據(jù)存儲到磁盤中诅蝶,并且釋放這些數(shù)據(jù)占用的內(nèi)存
- 換入:進程再次訪問這些內(nèi)存的時候逼友,把它們從磁盤讀取到內(nèi)存中
使用場景
Swap其實就是把系統(tǒng)的可用內(nèi)存變大了,即使服務(wù)器內(nèi)存不足秤涩,頁可用運行大內(nèi)存的應(yīng)用程序
- 內(nèi)存不足時帜乞,有些程序并不想被OOM殺死,而是希望能緩一段時間筐眷,等待人工介入或者等系統(tǒng)自動釋放其他進程的內(nèi)容黎烈,再分配給它就會用到swap
swap也是為了回收匿名頁占用的內(nèi)存
直接內(nèi)存回收:當(dāng)有大塊內(nèi)存分配請求,但是內(nèi)存不足匀谣,這時候系統(tǒng)就會回收一部分內(nèi)存(比如緩存)盡可能的滿足新內(nèi)存的請求照棋,這個過程叫做 直接內(nèi)存回收
定時內(nèi)存回收:內(nèi)核kswapd0線程用來定時回收內(nèi)存,為了衡量內(nèi)存的使用情況武翎,kswapd0定義了三個內(nèi)存閾值是 頁最小閾值(pages_min)烈炭,頁低閾值(pages_low)和頁高閾值(pages_high),剩余內(nèi)存則使用pages_free表示
- 剩余內(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)存壓力
頁低賦值可以通過內(nèi)核選項vm.min_free_kbytes
間接設(shè)置 /proc/sys/vm/min_free_kbytes丽蝎,min_free_kbytes設(shè)置了頁最小閾值,其他兩個閾值根據(jù)頁最小閾值計算生成的
pages_low = pages_min*5/4
pages_high = pages_min*3/2
NUMA與Swap
有時候系統(tǒng)內(nèi)存剩余還很多膀藐,但是Swap還是升高了屠阻,是因為處理器NUMA架構(gòu)導(dǎo)致的
在NUMA框架下,多個處理器被劃分到不同Node上额各,且每個Node 都擁有自己的本地內(nèi)存空間国觉,并且進一步又分為內(nèi)內(nèi)參域(zone),不如 直接內(nèi)存訪問區(qū)(DMA)臊泰,普通內(nèi)存區(qū)(NORMAL)蛉加,偽內(nèi)存區(qū)(MOVABLE)等
因為NUMA框架下每個Node都有自己的本地內(nèi)存空間蚜枢,所以分析內(nèi)存使用需要根據(jù)每個Node單獨分析, 可以通過numactl 查看每個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ù)這個輸出缸逃,我們系統(tǒng)中只有一個Node,就是Node0厂抽,編號為0 1 2 3的CPU都位于Node0上需频。另外Node0的內(nèi)存大小為 8191 MB,剩余1793 MB
前面提到的頁最小筷凤,頁低昭殉,頁高的三個閾值都可以在內(nèi)存域/proc/zoneinfo來查看
[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
上面輸出包含了三個內(nèi)存域的指標(biāo)苞七,min,low挪丢,high 就是上面提到的三個內(nèi)存閾值蹂风,而free是剩余內(nèi)存頁數(shù)它跟后面的nr_free_pages相同 注意: 這里單位是頁,每一頁是4kb乾蓬,比如計算頁最小閾值需要把 三個zone的min相加 * 4kb(9798 + 5530 + 30)* 4
根據(jù)輸入內(nèi)容發(fā)現(xiàn)pages free剩余內(nèi)存遠(yuǎn)高于high惠啄,所以此時kswapd0不會回收內(nèi)存,當(dāng)某個Node內(nèi)存不足時任内,系統(tǒng)可以從其他Node尋找空閑內(nèi)容撵渡,頁可以從本地內(nèi)存中回收內(nèi)存,需要選哪個模式死嗦,可以通過/proc/sys/vm/zone_reclaim_mode來調(diào)整
- 默認(rèn)為0趋距,也就是剛剛提到的模式,表示既可以從其他Node尋找空閑內(nèi)越除,頁可以從本地回收內(nèi)存节腐,這時候就會導(dǎo)致回收文件頁和匿名頁,匿名頁的回收所以會觸發(fā)swap
- 1摘盆,2铜跑,4,表示只回收本地內(nèi)存骡澈,2表示可以回收寫臟數(shù)據(jù)回收內(nèi)存锅纺,4表示可以用Swap方式回收內(nèi)存
swappiness
使用swap的積極程度可以通過內(nèi)核參數(shù) vm.swappiness 間接配置 /proc/sys/vm/swappiness 選項,配置范圍0-100肋殴,數(shù)字越大囤锉,越積極使用Swap,也就是更傾向于回收匿名頁护锤,數(shù)值越小官地,越消極使用Swap
即使你設(shè)置為0,當(dāng)剩余內(nèi)存文件頁小于高閾值時烙懦,還是會發(fā)生Swap
# 按VmSwap使用量對進程排序驱入,輸出進程名稱、進程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通過直接內(nèi)存回收和定時內(nèi)存掃描回收方式來釋放文件頁和匿名頁
- 文件頁的回收:就是直接回收緩存氯析,或者把臟數(shù)據(jù)寫回磁盤后釋放
- 匿名也的回收:需要通過Swap換出到磁盤中亏较,下次訪問時,在從磁盤換入到內(nèi)存中
定時內(nèi)存掃描回收方式的閾值可以通過內(nèi)核選項vm.min_free_kbytes
來設(shè)置
只要涉及到回收匿名頁就會涉及觸發(fā)Swap
假如沒有開啟swap的話掩缓,進程的匿名頁就無法釋放雪情,需要在進程的重啟或者殺掉釋放
swap使用積極程度可以通過內(nèi)核參數(shù)vm.swappiness 設(shè)置
在處理器NUMA框架下,每個Node都有自己的內(nèi)存域你辣,某個Node自己內(nèi)存域下剩余內(nèi)存不多情況下巡通,導(dǎo)致內(nèi)存回收也就有可能觸發(fā)Swap