Linux 內存統計

背景
由於Linux緩存機制的設計,系統對緩存的使用是非常狠的,所以經常會看到某些環境內存只剩幾十兆了,而應用只用了不到一半。所以在計算可用內存的時候,一定要算上緩存的部分。
通常方法,就是通過free命令首行free+cached+buffers計算,或者直接使用第二行的free字段。但這個方法有時仍然會造成比較大的誤差,導致性能監控等方面的問題。
比如系統中使用了大量的共享內存會造成多計算可用內存;再比如對大量的文件做了查詢(find / ?!!!
),會導致少計算可用內存。對於這點我在《說說free命令》中有詳細的說明。這裏就不再贅述了。
SUSE11 SP1基於2.6.32內核,內核暴露了更多的統計接口給用戶空間,把slab分爲可回收和不可回收兩類指標來統計。free命令也對應做了修改。解決了free命令少計算可用內存的問題。但多計算的問題還是存在。
因此,在這裏對統計可用內存的方法做了個總結。供需要的同學參考。(後面有空可能會開發一個統計工具)
其中SUSE10由於內核版本過低(2.6.16)暴露信息不足,下面的方法仍然不能很精確,但相比通過free命令簡單統計而言,一般不會造成比較大的誤差。

可用內存定義
包括未被使用的空閒內存,以及已經被使用但用作緩存可以自動回收的部分。

SUSE 10
可用內存統計方法
總內存free命令首行total字段。
空閒內存free命令首行free字段。
緩存free命令首行buffers字段+cached字段。
修正值1cached字段包含了共享內存和tmpfs內存文件系統佔用的內存。需要減去這兩部分。這兩部分內存可通過ipcs -m -udf 命令獲取。
修正值2cached字段漏掉了內核slab中可以自動回收的內存,比如xxx_inode_cachedentry_cache。這兩部分的內存的計算方法是解析/proc/slabinfo
最終的可用內存計算方法:
空閒內存+緩存-修正值1+修正值2

SUSE 11
可用內存統計方法
總內存free命令首行total字段。
空閒內存free命令首行free字段。
緩存free命令首行buffers字段+cached字段。
修正值1cached字段包含了共享內存和tmpfs內存文件系統佔用的內存。需要減去這兩部分。這兩部分內存之和可通過/proc/meminfoShmem字段直接獲取。
最終的可用內存計算方法:
空閒內存+緩存-修正值1

1ipcs獲取共享內存佔用物理內存大小
# ipcs -m -u
------ Shared Memory Status --------
segments allocated 4
pages allocated 786433
pages resident 2 #使用這個字段,單位是頁,X86下一個頁是4kB
pages swapped 0
Swap performance: 0 attempts 0 successes

2df獲取tmpfs佔用物理內存大小
# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 20972152 4427900 16544252 22% /
devtmpfs 24711780 160 24711620 1% /dev #Used字段表示實際佔用物理內存
tmpfs 24711780 0 24711780 0% /dev/shm #Used字段表示實際佔用物理內存
/dev/sda5 1052184 59188 992996 6% /boot
/dev/sda9 83888824 16852500 67036324 21% /iso
/dev/sda7 10490040 1142876 9347164 11% /opt
/dev/sda10 83888824 9421200 74467624 12% /src
/dev/sda8 20972152 3475104 17497048 17% /usr
/dev/sda6 5245016 328392 4916624 7% /var


///////////////////增加統計工具////////2011.6.29///////////////////////////////////////////////////
統計工具(SUSE10SUSE11驗證通過)
1.
修正可用內存多計算的情況(SUSE10 SUSE11
如下環境,在進行了大量共享內存創建使用後,free命令統計可用內存,出現了很大的誤差。
#echo 3 >/proc/sys/vm/drop_caches #清理可回收的內存
# free
total used free shared buffers cached
Mem: 49423560 13609680 35813880 0 26764
11686608 #仍有11G不可以回收,因爲是共享內存,不具備回收屬性。
-/+ buffers/cache: 1896308
47527252 # free計算可用內存,算入了共享內存,得到47G
Swap: 2104472 0 2104472
# ipcs -m -u
------ Shared Memory Status --------
segments allocated 20
pages allocated 4980737
pages resident 2883591 #共享內存有2883591 * 4 = 11534364 kB ~= 11G
pages swapped 0
Swap performance: 0 attempts 0 successes
# afree
Total: 49423560 kB #
物理內存總計
Free: 35816908 kB #
未被使用的內存
Reclaimable: 179348 kB #
被使用了但是可以自動回收的內存
Available: 35996256 kB #afree統計出來的可用內存去除了11G的共享內存。

2.
修正可用內存少計算的情況(SUSE10
如下環境,在進行了大量文件訪問操作後,系統中緩存了大概600Minodedentry
# free
total used free shared buffers cached
Mem: 3987316 1080908 2906408 0 163056 163848
-/+ buffers/cache: 754004
3233312 #沒有統計slab中的可以回收的inodedentry
Swap: 2104472 0 2104472
# afree
Total: 3987316 kB
Free: 2906384 kB
Reclaimable: 958888 kB
Available:
3865272 kB #afree統計了slab中的可以回收的inodedentry
# echo 3 >/proc/sys/vm/drop_caches #釋放600Minodedentry緩存。
# free
total used free shared buffers cached
Mem: 3987316 93628 3893688 0 17780 8948
-/+ buffers/cache: 66900
3920416 #執行drop_caches後,增加了600M,說明cached少統計了可回收的slab緩存。這600M即使不執行drop_caches也都是可用的,系統在需要的時候會自動回收。

注:afree通過解析slabinfo文件統計可回收的slab,其實suse10的內核有一個全局變量slab_reclaim_pages維護了準確的可回收數量,但沒有暴露給給用戶空間,因此更準確的方法其實就是寫一個模塊,把這個變量導出到來。
afree代碼如下:
#!/bin/sh
#
#Get accurate available memory.
#

function get_meminfo()
{
   grep -w $1 /proc/meminfo | awk -F' ' '{print $2}'
}
function show_meminfo()
{
   printf "%s\t%10d kB\n" "$1" "$2"
}

PAGE_SIZE=4 #kB, for x86
function get_shmem_from_ipcs()
{
   local _shm=0
   _shm=$(ipcs -m -u | grep 'pages resident' | awk -F' ' '{print $3}')
   echo $((_shm * PAGE_SIZE))
}
function get_tmpfs_from_df()
{
   local _size=""
   _size=$(df -k | awk -F' ' 'BEGIN{total=0} {if ($1 == "tmpfs" || $1 == "devtmpfs" || $1 == "shm")total+=$3}END{print total}')
   echo $_size 
}

#inode, dentry and buffer_head is reclaimable
function get_slab_reclaimable_from_slabinfo()
{
   local _size=""
   _size=$(awk -F' ' 'BEGIN{total=0} {if ($1~/inode/ || $1~"dentry" || $1 == "buffer_head")total+=($3 * $4)}END{printf "%d\n", total / 1024}' /proc/slabinfo)
   [ -z "$_size" ] && _size=0
   echo $_size 
}

free=$(get_meminfo MemFree)
total=$(get_meminfo MemTotal) 
cached=$(get_meminfo Cached)
buffer=$(get_meminfo Buffers)
swapcached=$(get_meminfo SwapCached)
shmem=$(get_meminfo Shmem)
slab_reclaimable=$(get_meminfo SReclaimable)
nfs_unstable=$(get_meminfo NFS_Unstable)

#the kernel does not support, no 'Shmem' field in /proc/meminfo, we use ipc and df.
if [ -z "$shmem" ] ; then
   shmem=$(( $(get_shmem_from_ipcs) + $(get_tmpfs_from_df) ))
fi

#the kernel does not support, no 'SReclaimable' field in /proc/meminfo, we use /proc/slabinfo.
if [ -z "$slab_reclaimable" ]; then
   slab_reclaimable=$(get_slab_reclaimable_from_slabinfo)
fi

#the kernel does not support, no 'NFS_Unstable' field in /proc/meminfo, we use null. :)
if [ -z "$nfs_unstable" ]; then 
   nfs_unstable=0
fi


reclaimable=$((cached + buffer + slab_reclaimable + swapcached + nfs_unstable - shmem))
available=$((free + reclaimable))
show_meminfo "Total: "       
說說free命令

free是個常用命令,幾乎每個接觸、使用linux的用戶都會用到它。但往往對它的統計輸出會有一些困惑,這一方面和Linux內存管理機制有關,另一方面Linux在內存統計上也確實有些不足和問題。

關鍵在於兩個字段,buffers和cached。
 
你經常會發現Linux系統用了一段時間後,內存所剩無幾,free命令,一看,內存全跑到 buffers和cached裏面了;這個現象是正常的。訪問過的磁盤文件的元數據及內容,內核都會緩存起來。這些緩存就是磁盤緩存。
 
Linux磁盤緩存設計特點(設計理念):
除了系統運行必須的一小部分保留外,只要有剩餘內存,只要需要,就會用給磁盤緩存。(沒有一個參數可以讓你限定緩存的上限。2.6內核之前有一個限定參數,後來給取消了)
所以會經常看到內存所剩無幾的現象,這是緩存機制導致的,對應用是透明,在有內存需要時,這些內存會釋放。這個過程對應用是透明的,應用可以認爲系統的可用內存包括buffers和cached。

這種設計,在大多數服務器應用場景下都有比較好的性能表現。可以說是比較可取的。
設計本身沒有問題,但free命令顯示的buffers和cached並不能和磁盤緩存完全對應,這是實現細節上的不足和問題。

1. buffers和cached包含了不屬於磁盤緩存的內容。
由於buffers和cached實際上就是內核爲所有文件映射分配的物理頁的總和(page cache)。
但內核中的“文件概念”是廣泛的,不僅包含了真正位於磁盤上的文件,還包含了爲特殊需要創建的虛擬文件,比如:
進程間的共享內存(通過shmget API創建的內存),內核建立一個虛擬的文件和共享內存關聯起來。(通過pmap命令你可以看到進程擁有的共享內存地址空間的映射字段是/SYSVXXXX字樣,不是匿名的)。
 
非常的不幸,這些虛擬文件映射關聯的page,也被算入了free命令顯示的cached字段。但這部分內存沒有緩存屬性,在內存不足時不能按緩存的方式來回收。(使用echo 3 >/proc/sys/vm/drop_caches,無法釋放掉這部分內存)
這個問題,會帶來一些麻煩。比如,按照常規理解,某產品設計內存佔用過高告警的條件是,空閒內存+buffers+cached小於內存總和的20% 。一般情況下沒有問題,但如果產品使用了大量的共享內存,告警將失去作用。
 
2. buffers和cached遺漏了部分屬於磁盤緩存的內容。
還 是由於buffers和cached只是內核爲所有文件映射分配的物理頁的總和。在文件系統方面,還有一部分緩存是不和文件映射相關聯的,比如內核分配的 inode對象,在文件關閉時,並不會立即釋放,具備緩存的屬性。這部分不在基於文件映射的頁面裏,而是通過slab(內核內存池)分配的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章