Linux有自己完备的一套内存回收机制,并不需要人为的干预,但它同时也提供了一种手动释放的手段,可以让我们在调试的时候使用,方法是通过设置"/proc/sys/vm/drop_cache"参数。
这个参数可接收3个数字的输入,分别是1, 2和3,写入1代表只释放page cache的可回收部分,写入2代表只释放slab cache中的可回收部分。可回收的slab cache是指在调用"kmem_cache_create"函数向slab分配器申请内存时,使用了"SLAB_RECLAIM_ACCOUNT"标志位,主要就是dentry cache和inode cache。
写入3代表同时释放page cache和reclaimable slab cache。很好记,1+2=3嘛,事实上,1就是二级制的01,2就是二进制的10,运行drop cache就是靠这两个置1的bit判断的。具体的实现函数是"drop_caches_sysctl_handler"(代码位于/fs/drop_caches.c):
int drop_caches_sysctl_handler(...){ if (sysctl_drop_caches & 1) { iterate_supers(drop_pagecache_sb, NULL); count_vm_event(DROP_PAGECACHE); } if (sysctl_drop_caches & 2) { drop_slab(); count_vm_event(DROP_SLAB); } ...}
写入后只会执行一次,后续不用再去管它,不需要写入0去清除什么的(其实你写入0也是不会成功的),如果非强迫症犯了想把它清掉,那就写入4好了,4是"100",末尾两位是0就行。
【page cache的释放】
在执行"echo 1 > /proc/sys/vm/drop_caches"命令之前和之后,分别查看"meminfo"中page cache的数量:
grep file /proc/meminfo Active(file): 1482380 kB Inactive(file): 527092 kB echo 1 > /proc/sys/vm/drop_caches grep file /proc/meminfo Active(file): 48572 kB Inactive(file): 17872 kB
可见,page cache所占用的内存明显减少,但并没有完全清空。因为这种方式只能清空page cache中"clean"的部分,也就是已经和外部磁盘同步过的部分。
因为"clean"的部分回收起来最简单,既然已经同步过了,直接丢弃即可,下次要用再从磁盘上拷贝回来就可以了,而"dirty"的部分需要先writeback到磁盘,才能释放。所以,"drop cache"准确地应该叫drop clean cache(如果想释放"dirty"的page cache,可以先使用"sync"命令强制同步一下)。
【slab cache的释放】
page cache对应的是文件系统中的文件数据(userdata),而inode cache对应的是文件系统中文件的控制结构(metadata)。对于磁盘文件系统,内存inode存在后备存储,因此同page cache一样,较易在内存中重建,释放的代价较低。dentry虽然在磁盘上没有直接对应的结构,但也可根据文件系统中目录inode的信息进行重建。
还是和之前page cache的实验一样,在执行"echo 2 > /proc/sys/vm/drop_caches"命令之前和之后,分别查看"meminfo"中slab cache的大小。
grep -A2 Slab /proc/meminfo Slab: 2329432 kB SReclaimable: 2257644 kB SUnreclaim: 71788 kB echo 2 > /proc/sys/vm/drop_caches grep -A2 Slab /proc/meminfo Slab: 113596 kB SReclaimable: 64380 kB SUnreclaim: 49216 kB
代表slab cache中可回收部分的"SReclaimable"明显减少,而代表不可回收部分的"SUnreclaim"的值基本没有变化。
再来看下回收前后dentry cache的数量变化,可见,处于"unused"状态的dcache被回收了 330984 - 6977 个
cat /proc/sys/fs/dentry-state 337552 330984 45 0 0 0 echo 2 > /proc/sys/vm/drop_caches cat /proc/sys/fs/dentry-state 13440 6977 45 0 0 0
而inode cache的数量,减少了410798-395270个:
cat /proc/sys/fs/inode-state 410798 1 0 0 0 0 0 echo 2 > /proc/sys/vm/drop_caches [root@dev yangcunfeng]# cat /proc/sys/fs/inode-state 395270 385875 0 0 0 0 0
一个内存inode被一个或多个dentry指向,如果指向一个inode的dentry都被释放,那么该inode也就没有继续存在于内存的意义,也会被同步释放,且由于这种指向关系,释放的inode object总数应略小于释放的dentry object的总数。
借助crash工具的"struct"命令,可以快速得知一个结构体的大小,以笔者使用的"4.18.0-80.el8.x86_64"内核版本为例,dentry和inode的结构体大小分别是208字节和648字节,计算一下,差不多就等于"SReclaimable"中减少的部分。
【小结】
清除page cache和slab cache可以快速释放内存,cache虽然占据了内存空间,但其本来就是为了提高性能而存在的,在手动清除后的一段时间里,系统的整体运行效率将受到影响。如果发现即便负责自动回收的kswapd频繁启动,系统的内存资源依然吃紧,应尝试去寻找部分内存始终不能有效释放的原因,手动清除并不能解决根本问题。
《本文》有 0 条评论