我的阿里云服务器,内存是2G,然后只是部署了一个博客,用docker部署了一个mysql和redis,过了一天在服务器上执行如下命令来查看内存使用情况:
free -h
上面标明我的总内存是1.8G,已经用了988M 剩余73M,我寻思不对啊,怎么会剩余这么少,然后看到后面的buff/cache占用775M,这个是什么鬼,计算下刚好等到如下公式:
total = used+free+buff/cache
执行如下命令查看前十个使用内存最大的进程:
ps -aux | sort -k4nr | head -10
我的程序加起来就占了44%,也就是差不多八百多兆,也就是,基本上都是buff/cache使用掉了,这里的buffer指Linux内存的:Buffer cache。这里的cache指Linux内存中的:Page cache。为了提高磁盘存取效率,Linux做了一些精心的设计,除了对dentry进行缓存(用于VFS,加速文件路径名到inode的转换),还采取了两种主要Cache方式:Buffer Cache和Page Cache。前者针对磁盘块的读写,后者针对文件inode的读写。这些Cache有效缩短了 I/O系统调用(比如read,write,getdents)的时间。
buffer cache
Buffer cache则主要是设计用来在系统对块设备进行读写的时候,对块进行数据缓存的系统来使用。这意味着某些对块的操作会使用buffer cache进行缓存,比如我们在格式化文件系统的时候。一般情况下两个缓存系统是一起配合使用的,比如当我们对一个文件进行写操作的时候,page cache的内容会被改变,而buffer cache则可以用来将page标记为不同的缓冲区,并记录是哪一个缓冲区被修改了。这样,内核在后续执行脏数据的回写(writeback)时,就不用将整个page写回,而只需要写回修改的部分即可。
Page cache
Page cache主要用来作为文件系统上的文件数据的缓存来用,尤其是针对当进程对文件有read/write操作的时候。
如何回收cache
Linux内核会在内存将要耗尽的时候,触发内存回收的工作,以便释放出内存给急需内存的进程使用。一般情况下,这个操作中主要的内存释放都来自于对buffer/cache的释放。尤其是被使用更多的cache空间。既然它主要用来做缓存,只是在内存够用的时候加快进程对文件的读写速度,那么在内存压力较大的情况下,当然有必要清空释放cache,作为free空间分给相关进程使用。所以一般情况下,我们认为buffer/cache空间可以被释放,这个理解是正确的。
但是这种清缓存的工作也并不是没有成本。理解cache是干什么的就可以明白清缓存必须保证cache中的数据跟对应文件中的数据一致,才能对cache进行释放。所以伴随着cache清除的行为的,一般都是系统IO飙高。因为内核要对比cache中的数据和对应硬盘文件上的数据是否一致,如果不一致需要写回,之后才能回收。
在系统中除了内存将被耗尽的时候可以清缓存以外,我们还可以使用下面这个文件来人工触发缓存清除的操作:
cat /proc/sys/vm/drop_caches
echo 1 > /proc/sys/vm/drop_caches
当然,这个文件可以设置的值分别为1、2、3。它们所表示的含义为:
echo 1 > /proc/sys/vm/drop_caches:表示清除pagecache。
echo 2 > /proc/sys/vm/drop_caches:表示清除回收slab分配器中的对象(包括目录项缓存和inode缓存)。slab分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的pagecache。
echo 3 > /proc/sys/vm/drop_caches:表示清除pagecache和slab分配器中的缓存对象。
这里执行第一个,后再free -h,会发现已经清理了。
总结
因为Linux内核会在内存将要耗尽的时候,触发内存回收的工作,以便释放出内存给急需内存的进程使用。一般情况下,这个操作中主要的内存释放都来自于对buffer/cache的释放,所以我觉得我们没有必要手动去清理,还是把值改为默认0好,这样可以有效缩短了 I/O系统调用。当然,不用echo 0的,他会自己恢复的,echo 0也会报错。-bash: echo: write error: Invalid argument。