一條報警引發的對 swap 認識

一個服務器報警信息

今天講一個排查問題的小故事吧.html

早上匆匆忙忙去上班了, 在一個例行的早會上, 意外被告知昨天 消息推送服務 內存報警, 超出了80%.bash

聽完後不禁的虎軀一震, 由於從業務上和平常報警上是沒有反饋的, 機器報警目前只報告給特定的運維團隊, 而且距離此事情已通過去一段時間了.服務器

抱着僥倖的內心, 登陸到報警的機器上查看相關指標markdown

首先查看了下負載、業務進程和相關日誌, 都沒有錯誤日誌記錄, 也沒有 OOM 被 kill 的記錄.運維

既然是內存報警, 先重點看下內存佔用狀況函數

free -m
複製代碼

能夠看到空餘內存仍是挺多的, 可是 Swap used保持在 149M 的佔用, 證實了確實出現過內存不夠使用的狀況, 具體緣由先不探究, 咱們看下 swap 相關知識點.oop

接下來引入咱們今天故事的主題 Swap

思考一個問題, 當操做系統內存不夠用的時會怎麼辦? 咱們知道磁盤通常被內存是廉價的, 而且存儲容量是很大的. 最好的辦法是將一部分當前不重要的數據放入磁盤來替代內存解燃眉之急.spa

其實,早期內存通常都比較小,很容易就出現內存不足的問題,因此很早就提出了一個交換分區(swap partition)的概念。操作系統

swap 分區是將磁盤看成內存使用,使得虛擬地址空間的範圍大小能夠超出物理內存的實際大小,在物理內存空間不足時,能夠將物理內存中的一些不重要數據拷貝到磁盤的 swap 分區中,從而讓出內存空間,而且在須要那些已被拷出數據時再從 swap 分區中拷回到內存,從而再也不那麼容易發生OOM錯誤。.net

只有在出現物理內存耗盡或即將耗盡的時候,若是進程繼續請求分配內存,將報錯 out-of-memory(OOM)表示內存不足,而且在出現 OOM 的時候,操做系統將觸發 OOM Killer 程序從進程列表中篩選出一個內存密集型進程殺掉,從而釋放大片內存

介紹完 swap 概念, 咱們看下指定進程佔用 swap 狀況

#找到進程ID編號爲 32132
cat /proc/32132/status
或
cat /proc/32132/smaps
複製代碼

咱們核心的幾個參數含義

VmPeak 進程所使用的虛擬內存的峯值
VmSize 進程當前使用的虛擬內存的大小
VmLck 已經鎖住的物理內存的大小(鎖住的物理內存不能交換到硬盤)
VmHWM 進程所使用的物理內存的峯值
VmRSS 進程當前使用的物理內存的大小
VmData 進程佔用的數據段大小
VmStk 進程佔用的棧大小
VmExe 進程佔用的代碼段大小(不包括庫)
VmLib 進程所加載的動態庫所佔用的內存大小(可能與其它進程共享)
VmPTE 進程佔用的頁表大小(交換表項數量)
VmSwap 進程所使用的交換區的大小
複製代碼

咱們能夠看到此進程佔用了 swap 交換區的 236kb

在上面參數含義中進程有虛擬內存、物理內存概念, 不知道你注意觀察過沒有, Top命令裏也有 VIRT、RES、SHR相關的參數, 這是什麼意思呢?

VIRT

一、進程「須要的」虛擬內存大小,包括進程使用的庫、代碼、數據,以及malloc、new分配的堆空間和分配的棧空間等;

二、假如進程新申請10MB的內存,但實際只使用了1MB,那麼它會增加10MB,而不是實際的1MB使用量。

三、VIRT = SWAP + RES

RES

一、進程當前使用的內存大小,包括使用中的malloc、new分配的堆空間和分配的棧空間,但不包括swap out量;

二、包含其餘進程的共享;

三、若是申請10MB的內存,實際使用1MB,它只增加1MB,與VIRT相反;

四、關於庫佔用內存的狀況,它只統計加載的庫文件所佔內存大小。

五、RES = CODE + DATA

SHR:

一、除了自身進程的共享內存,也包括其餘進程的共享內存;

二、雖然進程只使用了幾個共享庫的函數,但它包含了整個共享庫的大小;

三、計算某個進程所佔的物理內存大小公式:RES – SHR;

四、swap out後,它將會降下來。

堆、棧分配的內存,若是沒有使用是不會佔用實存的,只會記錄到虛存。若是程序佔用實存比較多,說明程序申請內存多,實際使用的空間也多。若是程序佔用虛存比較多,說明程序申請來不少空間,可是沒有使用。工做中,遇到過有的程序虛存300G+, 實存只有不到15G。

瞭解了這些內存的概念後咱們在從新回到 swap 上面來, 上面咱們經過指定 pid 能夠查看單個進程的 swap 佔用狀況, 我能夠清理或者重啓進程清理調 swap 佔用, 可是我如何快速列出到底是哪些進程 swap 佔用比較高呢.

查看佔用 swap 排名前10的進程pid

for i in $(cd /proc;ls | grep "^[0-9]"|awk '$0 >100');do awk '/Swap:/{a=a+$2}END{print "'$i'", a/1024"M"}' /proc/$i/smaps 2>/dev/null;done | sort -k2nr | head -10
複製代碼

通過重啓清理後, 從新觀察 swap 佔用狀況, 釋放了部分空間

關於 swap 其餘命令

開啓swap

# 含義爲增長1G的交換分區, 文件大小= bs * count
dd if=/dev/zero of=/root/swapfile bs=1M count=1024

mkswap /root/swapfile #創建swap的文件系統
swapon /root/swapfile #啓用swap文件
複製代碼

查看 swap 使用狀況

swapon -s
或
cat /proc/swaps
複製代碼

#關閉交換區
swapoff /root/swapfile 
#查看內存狀況
free -m 
複製代碼

咱們發現 Swap 項所有變爲了0, swapoff 能夠不用重啓進程快速釋放交互區數據, 但存在的風險是數據是有可能丟失的.

#從新開啓
swapon /root/swapfile 
#查看內存狀況
free -m 
複製代碼

參考文章

相關文章
相關標籤/搜索