【转载】【内存】为什么手工drop_caches之后cache值并未减少?
在Linux系统上查看内存使用状况最常用的命令是"free",其中buffers和cache通常被认为是可以回收的:
$ free
total used free shared buffers cached
Mem: 32764716 1067548 31697168 158332 12 593096
-/+ buffers/cache: 474440 32290276
Swap: 2103292 0 2103292
当内存紧张的时候,有一个常用的手段就是使用下面的命令来手工回收cache:
$ echo 1 > /proc/sys/vm/drop_caches
注:drop_caches
接受以下三种值:
-
To free pagecache:
echo 1 > /proc/sys/vm/drop_caches
-
To free reclaimable slab objects (includes dentries and inodes):
echo 2 > /proc/sys/vm/drop_caches
-
To free slab objects and pagecache:
echo 3 > /proc/sys/vm/drop_caches
当我们考虑有多少cache
可供回收的时候,首先要知道的是:不同版本的"free"命令计算cache值的算法不同,据不完全统计举例如下:
- 版本:procps-3.2.8-36
cache值等于/proc/meminfo
中的Cached
; - 版本:procps-3.3.9-10.1
cache值等于/proc/meminfo
的[Cached + SReclaimable]
; - 版本:procps-ng-3.3.10-3
cache值等于/proc/meminfo
的[Cached + Slab]
。
注:
/proc/meminfo
中的Cached
表示page cache
所占用的内存大小;
Slab
表示内核Slab
所占用的内存大小,slab有的可回收有的不可回收,其中可回收的通过SReclaimable
表示,不可回收的通过SUnreclaim
表示。
所以,对上述第2、3版本的"free"命令,echo 1 > /proc/sys/vm/drop_caches
对其中的SReclaimable
或Slab
部分是不起作用的。
即便仅考虑page cache
(对应于 /proc/meminfo
的Cached
),也并不是所有的页面都可以回收的:
首先,drop_caches
只回收clean pages
,不回收dirty pages
,参见https://www.kernel.org/doc/Documentation/sysctl/vm.txt
所以如果想回收更多的cache
,应该在drop_caches
之前先执行sync
命令,把dirty pages
变成clean pages
。
其次,即使提前执行了sync
命令,drop_cache
操作也不可能把cache值降到0,甚至有时候cache值几乎没有下降,这是为什么呢?因为page cache
中包含的tmpfs
和共享内存是不能通过drop_caches
回收的。
Page cache
用于缓存文件里的数据,不仅包括普通的磁盘文件,还包括了tmpfs
文件,tmpfs
文件系统是将一部分内存空间模拟成文件系统,由于背后并没有对应着磁盘,无法进行paging(换页),只能进行swapping(交换),在执行drop_cache
操作的时候tmpfs
对应的page cache
并不会回收。
我们通过实验来观察tmpfs
文件对free
命令的影响:
挂载一个3G大小的tmpfs:
$ mount -t tmpfs -o size=3G none /mytmpfs/
此时free命令看到的内存使用状况:
$ free
total used free shared buffers cached
Mem: 65942736 2343336 63599400 9492 8952 92848
-/+ buffers/cache: 2241536 63701200
Swap: 33038332 0 33038332
在tmpfs上新建一个2G大小的文件,free命令看到"cached"增加了2GB,注意"shared"也增加了2GB:
$ dd if=/dev/zero of=/mytmpfs/testfile bs=1G count=2
2+0 records in
2+0 records out
2147483648 bytes (2.1 GB) copied, 2.42736 s, 885 MB/s
$ free
total used free shared buffers cached
Mem: 65942736 4423404 61519332 2106644 9088 2190064
-/+ buffers/cache: 2224252 63718484
Swap: 33038332 0 33038332
执行drop_caches,再观察free命令的"cached"值,发现刚才增加的2GB并未被回收:
$ sync
$ sudo sh -c 'echo 1 > /proc/sys/vm/drop_caches'
$ free
total used free shared buffers cached
Mem: 65942736 4430388 61512348 2106644 5284 2183096
-/+ buffers/cache: 2242008 63700728
Swap: 33038332 0 33038332
最后删除tmpfs上的文件,free命令看到"Cached"和"Shared"同时减少2GB:
$ rm /mytmpfs/testfile
$ free
total used free shared buffers cached
Mem: 65942736 2324096 63618640 9784 6228 87412
-/+ buffers/cache: 2230456 63712280
Swap: 33038332 0 33038332
结论:
tmpfs占用的page cache
是不能通过drop_caches
操作回收的,tmpfs
占用的page cache
同时也算进了shared
中,也就是说,被视为共享内存。
Linux kernel利用tmpfs实现共享内存(shared memory
),参见:
https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt
所以共享内存也和tmpfs一样,属于page cache
,但又不能被drop_caches
回收。这里所说的共享内存包括:
SysV shared memory
是通过shmget申请的共享内存,用ipcs -m
或cat /proc/sysvipc/shm
查看;POSIX shared memory
是通过shm_open申请的共享内存,用ls /dev/shm
查看;shared anonymous mmap
通过mmap(…MAP_ANONYMOUS|MAP_SHARED…)
申请的内存,可以用pmap -x
或者cat /proc/<PID>/maps
查看;*
注:mmap
调用参数如果不是MAP_ANONYMOUS|MAP_SHARED
,则不属于tmpfs
,比如MAP_ANONYMOUS|MAP_PRIVATE
根本不属于pagecache
而是属于AnonPages
,MAP_SHARED
属于普通文件,对应的page cache
可以回写硬盘并回收。*
我们通过一个实验来观察共享内存对free命令的影响。以下程序通过shared anonymous mmap方式申请256MB大小的内存:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAP_SIZE 268435456
int main()
{
char *addr;
ssize_t s;
addr = mmap(NULL, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0);
if (addr == MAP_FAILED) {
fprintf(stderr, "mmap failed\n");
exit(EXIT_FAILURE);
}
memset(addr, 9, MAP_SIZE);
printf("mmap done, memset done, check free output. Press any key to exit...\n");
getchar();
exit(EXIT_SUCCESS);
}
实验过程如下:
先回收cache
,设置初始状态:
$ sync; sudo sh -c 'echo 1 > /proc/sys/vm/drop_caches'; free
total used free shared buffers cached
Mem: 65942736 2401684 63541052 9576 3648 54820
-/+ buffers/cache: 2343216 63599520
Swap: 33038332 0 33038332
然后执行我们的测试程序,申请256MB共享内存:
$ ./mmap_test
mmap done, memset done, check free output. Press any key to exit...
在另一个窗口里观察,看到cache
值增加了256MB,注意"shared"
也同时增加了256MB:
$ free
total used free shared buffers cached
Mem: 65942736 2652796 63289940 271720 6380 321760
-/+ buffers/cache: 2324656 63618080
Swap: 33038332 0 33038332
执行drop_caches
,发现刚才新增的256MBcache值并未被回收:
$ sync; sudo sh -c 'echo 1 > /proc/sys/vm/drop_caches'; free
total used free shared buffers cached
Mem: 65942736 2666452 63276284 271720 3628 316532
-/+ buffers/cache: 2346292 63596444
Swap: 33038332 0 33038332
退出mmap_test
程序,再看cache
值就减少了256MB,注意"shared"
也同时减少256MB:
$ free
total used free shared buffers cached
Mem: 65942736 2400268 63542468 9576 4796 59148
-/+ buffers/cache: 2336324 63606412
Swap: 33038332 0 33038332
结论:cache
值包含了共享内存的大小,然而drop_caches
是不能回收它的。
总结:为什么drop_caches操作不能回收所有的page cache?
dirty pages
不能回收;- 共享内存和
tmpfs
不能回收(注意观察free命令显示的shared值); - 不同版本的
free
命令有不同的计算cache
值的方法,有的包含了slab
或SReclaimable
,echo 1 > /proc/sys/vm/drop_caches
是不能回收slab的,echo 3 > /proc/sys/vm/drop_caches
也只是回收slab
中的SReclaimable
部分。
原文链接:https://mp.weixin.qq.com/s?__biz=MzAxOTk3OTgxOQ==&mid=2247483661&idx=1&sn=b53d42adb2b80c756c5ad51b637ea252 如有侵权,请联系作者删除!