在Linux系统中,我们经常用free
命令来查看系统内存的使用状态。在一个 CoreOS
的系统上,free
命令的显示内容大概是这样一个状态:
core@localhost ~ $ free
total used free shared buff/cache available
Mem: 8145320 391200 333888 204616 7420232 311660
Swap: 0 0 0
这里的默认显示单位是kb,我们可以通过添加-h
参数,来让free
命令显示的更为友好一些。
core@localhost ~ $ free -h
total used free shared buff/cache available
Mem: 7.8Gi 381Mi 0.3Gi 199Mi 7.4Gi 0.3Gi
Swap: 0B 0B 0B
新版linux相对来说已经好很多了,在老版的时候,是没有available
字段的。
所以放当时来说,大家可能会有下面几种反应:
free
之后,会觉得内存用了好多,我都没跑什么程序,内存就用完了!Linux好占内存!free
是没有多少了,但是真实内存才用了 400Mi 不到,还有很多剩余内存可用。buff/cache 占用比较多,说明系统中有进程曾经读写过文件,但是不要紧,这部分内存在系统内存吃紧的时候会释放出来的。但是,上面两种说法都有些片面了,都不是很正确。接下来让我们重新来认识一下buff
和cache
。
在Linux 2.4
的内存管理中,buffer
指Linux内存的:Buffer cache
。cache
指Linux内存中的:Page cache
。一般呢,是这么解释两者的。
翻译过来就是说:
所以 buffer
被用来当成对io设备写的缓存。而 cache
被用来当作对io设备的读缓存。这里的io设备,主要指的是块设备文件和文件系统上的普通文件。
但是在 Linux 2.6
以后,它们的意义不一样了。
在Linux 2.6
之后Linux将他们统一合并到了Page cache
作为文件层的缓存。而buffer
则被用作block
层的缓存。
block
层的缓存是什么意思呢,你可以认为一个buffer
是一个physical disk block
在内存的代表,用来将内存中的pages
映射为disk blocks
,这部分被使用的内存被叫做buffer
。
buffer
里面的pages
,指的是Page cache
中的pages
,所以,buffer
也可以被认为Page cache
的一部分。
或者简单来说,buffer
负责裸设备相关的缓存,cache
负责文件系统的缓存。
在当前的系统实现里,buffer
主要是设计用来在系统对块设备进行读写时作为缓存来使用。这意味着对块的操作会使用buffer
进行缓存,比如我们在格式化文件系统的时候。
但是一般情况下两个缓存系统是一起配合使用的,比如当我们对一个文件进行写操作的时候,cache
的内容会被改变,而buffer
则用来将cache
的page
标记为不同的缓冲区,并记录是哪一个缓冲区被修改了。
这样,内核在后续执行脏数据的回写(writeback
)时,就不用将整个page
写回,而只需要写回修改的部分即可。
cache
主要用来作为文件系统上的文件数据的缓存来用,当进程对文件有read/write
操作的时候。包括将文件映射到内存的系统调用mmap
,就会用到cache
。
因为cache
被作为文件类型的缓存来用,所以事实上也负责了大部分的块设备文件的缓存工作。
Linux内核会在内存将要耗尽的时候,自动触发内存回收的工作,以便释放出内存给急需内存的进程使用。
但是这种回收的工作也并不是没有成本。
理解cache
是干什么的就知道,cache
中存在着一部分write
操作的数据。所以必须保证cache
中的数据跟对应文件中的数据一致,才能对cache
进行释放。
于是伴随着cache
清除的行为的,一般都是系统IO
飙高。这是因为内核要将cache
中缓存的write
数据进行回写。
我们可以使用下面这个文件来人工触发缓存清除的操作,Linux 提供了三种清空方式:
echo 1 > /proc/sys/vm/drop_caches
# 仅清除页面缓存echo 2 > /proc/sys/vm/drop_caches
# 清除目录项和inodeecho 3 > /proc/sys/vm/drop_caches
# 清除页面缓存、目录项以及inode但是这种放时只能在执行的当时起作用,过一段时间之后又会发现内存被占满,怎么办呢?
实际上内核提供了vm.vfs_cache_pressure
参数用来控制缓冲区的回收频率,我们可以调整它。
这个参数是用来控制内核回收VFS缓存的频率。修改这个值会提高或者降低回收VFS缓存的频率。值可以设置为0-200
中的任意值。越大回收频率越快,可以把vm.vfs_cache_pressure
赋值为200
来获得最快的回收频率。这个值默认值一般为100
。
另外也可以使用slabtop
分析内存使用情况。一般情况下,dentry
和*_inode_cache
值越高回收的效果越好。
为什么是dentry
和*_inode_cache
呢,这是因为当读写文件时内核会为该文件对象建立一个dentry
,并将其缓存起来,方便下一次读写时直接从内存中取出提高效率。至于*_inode_cache
我就不是很清楚了,只知道是为了加快对索引节点的索引,如果有清楚的可以告诉我一下。
core@localhost ~ $ free -h
total used free shared buff/cache available
Mem: 7.8Gi 383Mi 7.1Gi 199Mi 291Mi 7.0Gi
Swap: 0B 0B 0B
core@localhost ~ $ dd if=/dev/zero of=testfile bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 1.39192 s, 753 MB/s
core@localhost ~ $ free -h
total used free shared buff/cache available
Mem: 7.8Gi 383Mi 6.1Gi 199Mi 1.3Gi 7.0Gi
Swap: 0B 0B 0B
core@localhost ~ $ echo 1 | sudo tee /proc/sys/vm/drop_caches
1
core@localhost ~ $ free -h
total used free shared buff/cache available
Mem: 7.8Gi 383Mi 7.1Gi 199Mi 291Mi 7.0Gi
Swap: 0B 0B 0B
core@localhost ~ $ time -p cat testfile > /dev/null
real 0.39
user 0.00
sys 0.27
core@localhost ~ $ free -h
total used free shared buff/cache available
Mem: 7.8Gi 382Mi 6.1Gi 199Mi 1.3Gi 7.0Gi
Swap: 0B 0B 0B
core@localhost ~ $ time -p cat testfile > /dev/null
real 0.17
user 0.00
sys 0.17