背景
由于Linux緩存機制的設計,系統對緩存的使用是非常狠的,是以經常會看到某些環境記憶體隻剩幾十兆了,而應用隻用了不到一半。是以在計算可用記憶體的時候,一定要算上緩存的部分。
通常方法,就是通過free指令首行free+cached+buffers計算,或者直接使用第二行的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可用記憶體統計方法
修正值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
segments allocated 20
pages allocated 4980737
pages resident 2883591 #共享記憶體有2883591 * 4 = 11534364 kB ~= 11G
# afree
Total: 49423560 kB #實體記憶體總計
Free: 35816908 kB #未被使用的記憶體
Reclaimable: 179348 kB #被使用了但是可以自動回收的記憶體
Available: 35996256 kB #afree統計出來的可用記憶體去除了11G的共享記憶體。
2. 修正可用記憶體少計算的情況(SUSE10)
如下環境,在進行了大量檔案通路操作後,系統中緩存了大概600M的inode和dentry。
Mem: 3987316 1080908 2906408 0 163056 163848
-/+ buffers/cache: 754004 3233312 #沒有統計slab中的可以回收的inode和dentry。
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緩存。
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()
_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
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)
#the kernel does not support, no 'NFS_Unstable' field in /proc/meminfo, we use null. :)
if [ -z "$nfs_unstable" ]; then
nfs_unstable=0
reclaimable=$((cached + buffer + slab_reclaimable + swapcached + nfs_unstable - shmem))
available=$((free + reclaimable))
show_meminfo "Total: "
說說free指令
關鍵在于兩個字段,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(核心記憶體池)配置設定的。
本文轉自feisky部落格園部落格,原文連結:http://www.cnblogs.com/feisky/archive/2012/04/14/2447503.html,如需轉載請自行聯系原作者