swap當咱們指的名詞的時候,它能夠是一個分區,也能夠是一個文件,是操做系統中一個存放從內存中置換出的數據的地方。 當咱們指的是一個動詞時候,表明的是從物理內存交換數據到swap分區這個動做。linux
(1) 當物理內存不夠用時候,會根據特定的算法,把一部份內存交換到swap分區(此時還會伴隨着高IO)。可是並非全部的內存均可以被交換到swap分區。 (2) kswapd進程週期性對內存進行檢查,若是發現高於水位線,則觸發swap,此舉是爲了避免讓系統剩餘內存不多,防止出現忽然的大內存申請。這塊暫不深刻講解,後續再補充。ios
首先咱們要知道,內存管理將內存分爲active和inactive,進程用戶空間使用的映射包括了匿名映射(anon)和文件映射(file)。全部一共有active anon,inactive anon,active file,inactive file。對於文件映射,因爲自己是磁盤空間中的文件,全部它不會被swap,當須要釋放時候,髒數據直接寫回磁盤,其餘數據直接釋放便可。內存交換到swap,確定是交換不活躍的數據,全部,inactive anon是最主要的被交換的內存。那麼對於操做系統來講,當我須要回收內存時候,你說它是針對文件映射好,仍是針對匿名映射好,這就涉及到了一個參數:swapinessgit
swapiness是設置內存回收時候,更傾向於回收文件映射仍是匿名映射,在/proc/sys/vm/swappiness設置值。對於swapiness=100,那麼二者之間的權重是一致的,值越小,越傾向於回收文件映射,不過若是達到系統高水位線,仍是會swap,除非直接使用swapoff -a等手段關閉系統swap。github
swap的好處是當內存不足時候,能夠將一部分交換出去,不會觸發oom-killer。跑得慢總比不能跑好。 swap的壞處是交換時候,會觸發高IO,同時會下降系統的性能。對於咱們隔離作的很差的時候,會影響到其餘應用的性能。golang
一個工具每每具備多種用途,可是本文只說明針對swap問題算法
工具名稱 | 使用姿式 | 採集指標來源 |
---|---|---|
free | free -h | /proc/meminfo |
top | 按f,選擇swap | /proc/$pid/smaps |
vmstat | vmstat | /proc/meminfo |
iotop | iotop | |
iostat | iostat -xdm | |
pidstat | pidstat -d 1 | /proc/$pid/io |
本次的案例是使用golang編寫,在一個死循環裏面,每次循環申請內存,而且不釋放,而後達到必定次數後釋放內存,等待GC,再繼續,代碼和文檔歸檔在:歸檔。docker
(1) 運行api
root@szdc-calic-2-6:/www/linuxperformancetool/swap# ./swapexample1
複製代碼
因爲上面說的命令均可以用於分析,你們根據喜愛搭配使用便可。我這裏用top,vmstat和pidstat搭配使用進行分析,能夠開多幾個終端一塊兒看。bash
(2) 分析 首先是使用vmstat,從下面能夠看出,當程序佔用內存愈來愈大時候,出現了很高的swap io和block io,想一下,爲何這兩個同時都增高?app
root@szdc-calic-2-6:~# vmstat -a 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free inact active si so bi bo in cs us sy id wa st
1 0 1240208 18816440 715216 12702360 0 0 1 18 0 0 0 0 99 0 0
1 0 1240208 18086504 715220 13431988 0 0 0 0 2223 3192 1 4 96 0 0
1 0 1240208 17343176 715220 14173444 0 0 0 60 1906 3099 1 4 95 0 0
1 0 1240208 16618392 715260 14897140 0 0 0 60 2351 3552 1 4 96 0 0
1 0 1240208 15883220 715280 15632572 0 0 0 0 2187 3547 1 4 96 0 0
0 2 1240300 15276012 806532 16151868 0 92 0 2088 2365 3373 1 3 95 2 0
0 2 1265792 15270100 2023920 14946200 56 25500 100 27536 5102 9189 1 1 93 5 0
0 3 1265784 15274476 2023856 14944732 40 0 40 2572 2162 2425 0 0 90 10 0
0 9 1287036 15276116 2022816 14944232 88 21276 88 22228 2074 3136 0 0 79 21 0
0 9 1287020 15273676 2024776 14946436 92 0 92 2288 3563 5822 0 0 79 20 0
2 3 1286912 15271708 2024844 14946532 128 0 128 1432 2989 4907 0 0 84 16 0
0 3 1286912 15271692 2024572 14946520 0 0 0 2344 3098 4543 0 0 87 13 0
0 4 1312096 15265788 2022444 14951064 0 25188 0 26628 4946 9752 1 1 90 9 0
複製代碼
發現了系統問題後,咱們就須要對問題進行定位了,這裏可使用top,pidstat,iotop等工具進行定位,我這邊直接使用top,按f選擇swap。
top - 00:52:38 up 253 days, 14:23, 3 users, load average: 6.44, 2.60, 1.23
Tasks: 359 total, 1 running, 358 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.6 us, 0.6 sy, 0.0 ni, 67.0 id, 31.7 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 32895096 total, 236100 free, 32011520 used, 647476 buff/cache
KiB Swap: 31250428 total, 28358956 free, 2891472 used. 261616 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND SWAP
45466 root 20 0 10.076g 21624 2520 S 12.9 0.1 7881:36 etcd 19636
146 root 20 0 0 0 0 D 9.2 0.0 2:28.44 kswapd0 0
14179 root 20 0 31.136g 0.029t 4316 S 3.3 94.8 0:31.86 main1 1.375g
147 root 20 0 0 0 0 S 1.7 0.0 1:52.23 kswapd1 0
10737 root 20 0 3067756 60688 5968 S 0.7 0.2 3364:41 dockerd 60380
10750 root 20 0 2898452 38724 3096 S 0.7 0.1 629:49.22 docker-containe 79288
複製代碼
從top的變化能夠看出,pid=14179的進程一直swap一直在增高,並且內存佔用愈來愈高,其餘進程雖然有出現swap增多,可是內存使用並無增高,能夠判斷,該進程是致使出現swap的緣由。那麼,咱們再進一步進行確認。
使用pidstat判斷該pid的io狀況,能夠看出,是存在很大的IO
root@szdc-calic-2-6:~# pidstat -p 14179 -d 1
Linux 4.4.0-87-generic (szdc-calic-2-6.meitu-inc.com) Wednesday, December 12, 2018 _x86_64_ (24 CPU)
12:55:40 CST UID PID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
12:55:41 CST 0 14179 71920.00 0.00 0.00 0 main1
12:55:42 CST 0 14179 72796.04 0.00 0.00 0 main1
12:55:43 CST 0 14179 85664.00 0.00 0.00 0 main1
12:55:44 CST 0 14179 78128.00 0.00 0.00 0 main1
12:55:45 CST 0 14179 69660.00 0.00 0.00 0 main1
12:55:46 CST 0 14179 59892.00 0.00 0.00 0 main1
複製代碼
這些問題都不會直接進行解答,實在想不出來的,能夠到歸檔項目下面提issue或者在下面評論
(1) 爲何例子中,只是簡單的申請內存,會形成swap io和block io同時增高? (2) 例子中,明明還有剩餘內存未被使用,但是已經開始頻繁進行swap和回收大量內存。 (3) golang gc時候,會把已經swap出去的內存再swap到物理內存中,再進行gc嗎? (4) 上一節中的buffer和cache中包含的是哪些?(匿名頁仍是文件映射)