最近有好几位同事问我关于free(1)结果中buffers和cached的区别,一直很佩服@淘宝褚霸 对知识的无私分享,所以今天就以这个话题开始我的blog吧,但愿有机会时常更新它,争取2012年能够做到至少一个月一篇吧,呵呵!闲话少说,进入正题。
free命令大家都经常使用,
taotaoma@tma-laptop1:~/kernel/linux-2.6$ free
total used free shared buffers cached
Mem: 5918476 1675260 4243216 0 157664 819004
-/+ buffers/cache: 698592 5219884
Swap: 0 0 0
各个内容的显示应该还算是简单明了的,唯一比较让人困惑的两项就是buffers和cached。一般的认识都是说buffers指的是元数据的数量,而cached是指文件的page cache的数量。那么真的是这样么?
其 实现在的linux内核中对于缓存的管理都是以page的形式进行的,也就是说在系统底层只存在各种page,这些page保存在不同的tree 中,buffer这个概念实际上已经过时了,但是为了保持对过往系统的兼容性,linux内核中还保留了这个概念,并仍然用它来代表文件系统中的一些所谓的元数据,但是由于已经没有buffer了,那么free该怎么显示buffers呢?内核巧妙的利用了一个特性,那就是文件系统在读取元数据的时候一般都是通过它所对应的块设备来进行,也就是说元数据存储的page一般都是保存在块设备对应的tree中,而一般文件的page cache则是保存在它的宿主文件的tree中。有了这个假设,我们就可以通过统计所有在块设备的tree上的page来得出系统的buffers数量。
这一块对应的代码是这样的(以2.6.32的代码为例):
free是通过读取/proc/meminfo里面的数据来显示的,而/proc/meminfo的具体实现代码在Linux内核中的fs/proc/meminfo.c里面。
sysinfo.bufferram是通过函数si_meminfo得到的,查看si_memeinfo可以看到这样一行:
val->bufferram = nr_blockdev_pages();
而对应的函数就很简单了
long nr_blockdev_pages(void)
{
struct block_device *bdev;
long ret = 0;
spin_lock(&bdev_lock);
list_for_each_entry(bdev, &all_bdevs, bd_list) {
ret += bdev->bd_inode->i_mapping->nrpages;
}
spin_unlock(&bdev_lock);
return ret;
}
遍历所有的块设备,然后把所有的块设备tree上的pages数目加起来,然后返回,是不是一目了然呢!
问题到这里真的就结束了么?非也非也,这样的算法明显很不精确,因为如果我直接操作裸设备,那内核如何区分呢?大家可以做一个简单的测试。
echo 3 > /proc/sys/vm/drop_caches
free
dd if=/dev/sda of=/dev/null bs=1M count=1000
free
相信大家一定都看到了buffers的剧烈增长了吧!由于你像文件系统一样直接通过块设备来读取设备的内容,所以内核把你这次操作读取的page都算作了buffers,也就从侧面验证了free命令中计算buffers所用的算法。
转载请注明:爱开源 » free命令中的buffers和cached