Linux 清理内存缓存

Linux 清理内存缓存

Linux Kernel 的内存占用一直是个谜,最近在 PVE 虚拟机里面安装了 Debian 12,发现内存占用一直居高不下,分多少 GB 就占用多少 GB,和服务器里面安装的 1Panel 面板中显示的数据不符,尝试更换为 Ubuntu Server 也没有解决

经过查询资料发现, Linux Kernel 本来就是这么设计的,这是正常现象

但对于我来说,这个事实不符合我的预期,因为我的 PVE 宿主机只有 8 GB 内存,刚好最近内存价格又有点小涨,消费不起

不过这个问题是可以在 Linux 内核性能调优方面做到的,下面简单说一下

原理

参考:https://www.kernel.org/doc/html/latest/admin-guide/sysctl/vm.html

简单说明一下,Linux 的 VFS(虚拟文件系统)会把系统读取和写入的数据缓存到内存中,类似 CDN,如果内存中已有缓存(命中缓存),就不会到硬盘中读取(回源),这也就是 Linux Server 性能比 WinServer 强的其中一个原因

知道这些够了,如果再深入研究,得从 Linux kernel 的原理/源码啃起了,但没必要

可以使用 free 命令轻松查询到「buff/cache」就是缓存

1
2
3
4
root@debian:~# free -h
total used free shared buff/cache available
Mem: 1.9Gi 707Mi 122Mi 4.2Mi 1.3Gi 1.2Gi
Swap: 0B 0B 0B

可以看到这个 2 GB 的内存只使用了 707 MB,但空出来的只有 122 MB(和 PVE 中显示的基本一致),但可用内存却有 1.2 GB(和面板中显示的一致),有 1.3 GB 的内存不知道去哪里了,哦,现在知道了,被企鹅🐧吃了

本人企鹅图标的没啥好感,特别是内存这块,另外一只患了NT的企鹅🐧也特别喜欢吃内存

当然也可以直接查询内核内存信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
root@debian:~# cat /proc/meminfo 
MemTotal: 2014324 kB
MemFree: 1025480 kB
MemAvailable: 1330928 kB
Buffers: 8236 kB
Cached: 426356 kB
SwapCached: 0 kB
Active: 376272 kB
Inactive: 441292 kB
Active(anon): 251124 kB
Inactive(anon): 144852 kB
Active(file): 125148 kB
Inactive(file): 296440 kB
Unevictable: 27428 kB
Mlocked: 27428 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Zswap: 0 kB
Zswapped: 0 kB
Dirty: 28 kB
Writeback: 0 kB
AnonPages: 410428 kB
Mapped: 410396 kB
Shmem: 4272 kB
KReclaimable: 31076 kB
Slab: 88356 kB
SReclaimable: 31076 kB
SUnreclaim: 57280 kB
KernelStack: 4848 kB
PageTables: 9340 kB
SecPageTables: 0 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 1007160 kB
Committed_AS: 1910468 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 16916 kB
VmallocChunk: 0 kB
Percpu: 2576 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
FileHugePages: 0 kB
FilePmdMapped: 0 kB
Unaccepted: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 0 kB
DirectMap4k: 94056 kB
DirectMap2M: 2002944 kB
DirectMap1G: 0 kB

太长了,算了还是用 free 命令吧

临时解决

先存盘,最大限度地清理内存(dirty objects)

1
sync

清理内存

  1. 只清理「页面缓存(PageCache)」:

    1
    echo 1 > /proc/sys/vm/drop_caches
  2. 只清理「slab 分配的可回收对象」(包括 dentries 和 inodes):

    1
    echo 2 > /proc/sys/vm/drop_caches
  3. 清理上面俩玩意:

    1
    echo 3 > /proc/sys/vm/drop_caches

此时就会将这些缓存从内存中清理出去,到 PVE 宿主机上就可以看到内存占用大幅降低

这种方式可以临时降低虚拟机内存对宿主机的占用,适合临时需要空出内存的情况

但这只是临时的而不是永久生效,如需定期清理,可以配置 crontab 脚本

1
2
3
#!/bin/bash
sync
echo "echo 3 > /proc/sys/vm/drop_caches"

彻底解决

如果需要彻底解决这个问题,我们可以直接修改 sysctl

1
vim /etc/sysctl.conf

增加或修改以下内容

1
vm.vfs_cache_pressure = 100

1
vm.vfs_cache_pressure = 500

该文件表示内核回收用于directory和inode cache内存的倾向

  • 默认值是100,表示内核将根据pagecache和swapcache,把dentries和inodes的缓存保持在一个合理的百分比

  • 低于100,将导致内核倾向于保留dentries和inodes的缓存,比如说设成0就不会自动清理

  • 超过100,将导致内核倾向于回收dentries和inodes的缓存,比如说设成1000就会比之前增加10倍的清理次数

然后执行

1
sysctl -p

这样会增加内核自动清理缓存的频率

也可以临时生效:

1
2
sysctl -w vm.vfs_cache_pressure=500
sysctl -p

最终方案

不就是 2 GB 内存多了给应用程序用不完,才用来做磁盘缓存吗?

直接分给它 1 GB,从根本上解决问题

顺便提高内存容量利用效率,还可以降低异常断电内存数据未回写到硬盘导致大量数据丢失的风险

别和我扯什么“内存分少了速度慢”,朕的宿主机内存不允许,还不只能占用硬盘做 SWAP

反正这个问题属于正常情况,系统会自动清理的,Linux kernel设计出来就是开箱即用的,默认设置考虑了大多数的情况,实体机不用管