記一次內存佔用問題的調查過程

最近在維護一臺CentOS服務器的時候,發現內存無故"損失"了許多,free和ps統計的結果相差十幾個G,搞的我一度又覺得遇到靈異事件了,後來Google了許久才搞明白,特此記錄一下,以供往後查詢。php

雖然每天都在用Linux系統辦公,其實對它的瞭解也不過爾爾。畢業幾年才邁入"知道本身不知道"的境界,我以爲本身絲毫沒有愧對萬年吊車尾這個稱號 :(html

問題描述和初步調查

同事說有一臺服務器的內存用光了,我連上去用free看了下,確實有點怪。node

$ free -g
             total       used       free     shared    buffers     cached
Mem:            15         15          0          0          2          0
-/+ buffers/cache:         12          2
Swap:           17          0         17

這臺服務器有16G內存,可是結果顯示除了2G左右的文件Buffer緩存外,其他十幾G都被確確實實的用光了。(free按1024進制計算,總內存可能比實際偏小)linux

這裏大概介紹下free結果的含義:緩存

/ total used free shared buffers cached
Mem 總物理內存 當前使用的內存(包括slab+buffers+cached) 徹底沒有使用的內存 進程間共享的內存 緩存文件的元數據1 緩存文件的具體內容1
-/+ buffers/cache
當前使用的內存(不包括buffers+cached,但包括slab) 未使用和緩存的內存(free+buffers+cached)


Swap 總的交換空間 已使用的交換空間 未使用的交換空間


而後top看了下,沒有特別吃內存的程序。用ps大概統計下全部程序佔用的總內存:服務器

$ ps aux | awk '{mem += $6} END {print mem/1024/1024}'
0.595089

結果顯示全部進程佔用的內存還不到1G,實際上,由於free, ps的統計方式的差異和Copy-on-writeShared libraries等內存優化機制的存在,這二者的統計結果一般是不同的。可是通常狀況下絕對不會相差十幾個G,確定是有什麼隱藏的問題,Google了許久後發現,free沒有專門統計另外一項緩存: Slab。app

Slab簡介和進一步調查

Slab Allocation是Linux 2.2以後引入的一個內存管理機制,專門用於緩存內核的數據對象,能夠理解爲一個內核專用的對象池,能夠提升系統性能並減小內存碎片。(Linux 2.6.23以後,SLUB成爲了默認的allocator。)ide

查看Slab緩存性能

$ cat /proc/meminfo

其中,Slab相關的數據爲測試

Slab:             154212 kB
SReclaimable:      87980 kB
SUnreclaim:        66232 kB

SReclaimable(Linux 2.6.19+)都是clean的緩存,隨時能夠釋放。回到以前的內存問題,我查了下那臺服務器上Slab佔用的內存:

$ cat /proc/meminfo | grep Slab
Slab:         12777668 kB

12G的Slab緩存,有意思的是free把Slab緩存統計到了used memory中,這就是以前那個問題的癥結所在了。

另外,還能夠查看/proc/slabinfo(或使用slabtop命令)來查看Slab緩存的具體使用狀況。結果發現,ext3_inode_cache和dentry_cache佔用了絕大部份內存。

考慮到這臺服務器會頻繁地用rsync同步大量的文件,這個結果也並不意外。

解決問題

先說明一下,若是問題僅僅是Slab佔用了太多的內存(SReclaimable),那麼一般不須要太操心,由於這根本不是個問題(若是是SUnreclaim太多且不斷增加,那麼頗有多是內核有bug)。可是,若是是由於Slab佔用內存太多而引發了其餘的問題,建議繼續閱讀。

清除Slab可回收緩存

經過/proc/sys/vm/drop_caches這個配置項,咱們能夠手動清除指定的可回收緩存(SReclaimable)2

echo 2 > /proc/sys/vm/drop_caches

上面的命令會主動釋放Slab中clean的緩存(包括inode和dentry的緩存),而後再free -g一下,未使用的內存陡增了十幾個G。。。

須要注意的是,手動清除緩存可能會在一段時間內下降系統性能。原則上不推薦這麼作,由於若是有須要,系統會自動釋放出內存供其餘程序使用。

另外,手動清除Slab緩存是一個治標不治本的辦法。由於問題不在Slab,而在於咱們那個會引發Slab緩存飆漲的進程(我這裏應該是rsync)。實際操做的時候發現,清除緩存一段時間後,Slab緩存很快又會「反彈」回去。若是須要治本,要麼搞定問題進程,要麼修改系統配置。

調整系統vm配置

風險預警: 調整如下系統配置可能會對系統性能形成負面影響,請仔細測試並謹慎操做

/etc/sysctl.conf裏有幾個對內存管理影響比較大的配置,如下配置項的文檔見vm.txt

vm.vfs_cache_pressure

系統在進行內存回收時,會先回收page cache, inode cache, dentry cache和swap cache。vfs_cache_pressure越大,每次回收時,inode cache和dentry cache所佔比例越大3

vfs_cache_pressure默認是100,值越大inode cache和dentry cache的回收速度會越快,越小則回收越慢,爲0的時候徹底不回收(OOM!)。

linux io caches

圖片取自The Linux Kernel's VFS Layer

vm.min_free_kbytes

系統的"保留內存"的大小,"保留內存"用於低內存狀態下的"atomic memory allocation requests"(eg. kmalloc + GFP_ATOMIC),該參數也被用於計算開始內存回收的閥值,默認在開機的時候根據當前的內存計算所得,越大則表示系統會越早開始內存回收

min_free_kbytes過大可能會致使OOM,過小可能會致使系統出現死鎖等問題。

vm.swappiness

該配置用於控制系統將內存swap out到交換空間的積極性,取值範圍是[0, 100]。swappiness越大,系統的交換積極性越高,默認是60,若是爲0則不會進行交換。

相關文章
相關標籤/搜索