Linux可用内存统计方法

本文深入探讨了Linux系统内存管理机制,详细解释了如何准确计算可用内存,包括修正内存计算误差的方法,并提供了针对不同内核版本的可用内存统计公式。通过解析系统命令输出和内核统计接口,文章揭示了如何避免误算内存,从而提供更精确的内存使用情况分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景
由于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 2471178016024711620 1% /dev#Used字段表示实际占用物理内存
tmpfs 24711780024711780 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 usedfreeshared buffers cached
Mem: 49423560 13609680 35813880 0 2676411686608 #仍有11G不可以回收,因为是共享内存,不具备回收属性。
-/+ buffers/cache: 189630847527252 # 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 usedfree shared buffers cached
Mem: 3987316 1080908 2906408 0 163056 163848
-/+ buffers/cache: 7540043233312 #没有统计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: 669003920416 #执行drop_caches后,增加了600M,说明cached少统计了可回收的slab缓存。这600M即使不执行drop_caches也都是可用的,系统在需要的时候会自动回收。

注:afree通过解析slabinfo文件统计可回收的slab,其实suse10的内核有一个全局变量slab_reclaim_pages维护了准确的可回收数量,但没有暴露给给用户空间,因此更准确的方法其实就是写一个模块,把这个变量导出到来。

afree代码如下:

#!/bin/sh
#
#Get accurate available memory.
#

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

PAGE_SIZE=4#kB, for x86
functionget_shmem_from_ipcs()
{
local_shm=0
_shm=$(ipcs -m -u|grep'pages resident'|awk -F'''{print $3}')
echo$((_shm * PAGE_SIZE))
}
functionget_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
functionget_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:""$total"
show_meminfo"Free:""$free"
show_meminfo"Reclaimable:""$reclaimable"
show_meminfo"Available:""$available"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值