日期:2014-05-16  浏览次数:20763 次

linux中的buffer和cache

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 (buffer的数量增加了1000M)

? ? 相信大家一定都看到了buffers的剧烈增长了吧!由于你像文件系统一样直接通过块设备来读取设备的内容,所以内核把你这次操作读取的page都算作了buffers,也就从侧面验证了free命令中计算buffers所用的算法。

?

写数据到文件系统的文件中:

echo 3 > /proc/sys/vm/drop_caches

dd if=/dev/zero of=200Mfile bs=100M count=2

free (cache的数量增加了200M, buffer几乎不变)

?

读文件系统的文件

echo 3 > /proc/sys/vm/drop_caches

if=14GB_largefile of=/