背景
由於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字段。
修正值1:cached字段包含了共享內存和tmpfs內存文件系統占用的內存。需要減去這兩部分。這兩部分內存可通過ipcs -m -u和df 命令獲取。
修正值2:cached字段漏掉了內核slab中可以自動回收的內存,比如xxx_inode_cache和dentry_cache。這兩部分的內存的計算方法是解析/proc/slabinfo。
最終的可用內存計算方法:
空閑內存+緩存-修正值1+修正值2
SUSE 11可用內存統計方法
總內存:free命令首行total字段。
空閑內存:free命令首行free字段。
緩存:free命令首行buffers字段+cached字段。
修正值1:cached字段包含了共享內存和tmpfs內存文件系統占用的內存。需要減去這兩部分。這兩部分內存之和可通過/proc/meminfo的Shmem字段直接獲取。
最終的可用內存計算方法:
空閑內存+緩存-修正值1
附1:ipcs獲取共享內存占用物理內存大小
# 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
附2:df獲取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///////////////////////////////////////////////////
統計工具(在SUSE10、SUSE11驗證通過)
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)
如下環境,在進行了大量文件訪問操作后,系統中緩存了大概600M的inode和dentry。
# free
total used free shared buffers cached
Mem: 3987316 1080908 2906408 0 163056 163848
-/+ buffers/cache: 754004 3233312 #沒有統計slab中的可以回收的inode和dentry。
Swap: 2104472 0 2104472
# afree
Total: 3987316 kB
Free: 2906384 kB
Reclaimable: 958888 kB
Available: 3865272 kB #afree統計了slab中的可以回收的inode和dentry。
# echo 3 >/proc/sys/vm/drop_caches #釋放600M的inode和dentry緩存。
# 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(內核內存池)分配的。
原文:http://yalung929.blog.163.com/blog/static/203898225201223102617451/