【linux】关于内存free转换到buffer/cache之后,内存被用完的解决思路

关于内存free转换到buffer/cache之后,内存被用完的解决思路

最近跑程序,发现linux在执行大量读写操作后,内存的可用(free)会不断被buffer/cache所占据,导致内存空间被用完,一直以为是代码哪里写的问题,导致内存泄露,后来发现就是发生了I/O读写操作后,会产生buffer/cache,需要定时释放。

这个情况也是第一次遇到,不知道如何解决

问了chatgpt是这么解释的:
在这里插入图片描述

1.可用内存不断减少问题现象

执行free -m查询内存状态
在这里插入图片描述
发现内存越来越少了

2.排查方案:用hcache检查buffer/cache 过高如何排查是由那几个进程引起的

hcache安装

sudo wget https://silenceshell-1255345740.cos.ap-shanghai.myqcloud.com/hcache -O /usr/local/bin/hcache ;\
chmod +x /usr/local/bin/hcache

2.1hcache命令查询最大buffer/cache进程号

2.1.1 全局显示10个最大的被缓存文件

hcache --top 10 全局显示10个最大的被缓存文件

hcache --top 10 
+------------------------------------------------------------------+----------------+------------+-----------+---------+
| Name                                                             | Size (bytes)   | Pages      | Cached    | Percent |
|------------------------------------------------------------------+----------------+------------+-----------+---------|
| /usr/bin/dockerd                                                 | 95731632       | 23372      | 16990     | 072.694 |
| /usr/bin/containerd                                              | 52008056       | 12698      | 10690     | 084.186 |
| /usr/lib/x86_64-linux-gnu/libLLVM-13.so.1                        | 99813728       | 24369      | 9785      | 040.153 |
| /snap/snapd/19457/usr/lib/snapd/snapd                            | 33291328       | 8128       | 7488      | 092.126 |
| /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so                      | 25006904       | 6106       | 2986      | 048.903 |
| /usr/lib/x86_64-linux-gnu/libwebkit2gtk-4.0.so.37.63.4           | 73062112       | 17838      | 2641      | 014.805 |
| /usr/lib/x86_64-linux-gnu/libmozjs-91.so.91.10.0                 | 12184728       | 2975       | 2634      | 088.538 |
| /usr/bin/containerd-shim-runc-v2                                 | 9489240        | 2317       | 2306      | 099.525 |
| /var/log/journal/56abef55033544eaab9e41b9caf03250/system.journal | 8388608        | 2048       | 1216      | 059.375 |
| /usr/bin/python3.10                                              | 5913032        | 1444       | 1175      | 081.371 |
+------------------------------------------------------------------+----------------+------------+-----------+---------+
2.1.2 查询第一个的进程号
lsof /usr/bin/dockerd
COMMAND  PID USER  FD   TYPE DEVICE SIZE/OFF     NODE NAME
dockerd 1099 root txt    REG   8,18 95731632 17564073 /usr/bin/dockerd
2.1.3 取当前进程号所打开的所有文件信息
2.1.3.1 hcache
hcache -pid 1099
+--------------------------------------------------+----------------+------------+-----------+---------+
| Name                                             | Size (bytes)   | Pages      | Cached    | Percent |
|--------------------------------------------------+----------------+------------+-----------+---------|
| /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2   | 240936         | 59         | 59        | 100.000 |
| /var/lib/docker/buildkit/snapshots.db            | 16384          | 4          | 4         | 100.000 |
| /usr/lib/x86_64-linux-gnu/libnss_systemd.so.2    | 309600         | 76         | 76        | 100.000 |
| /var/lib/docker/volumes/metadata.db              | 65536          | 16         | 11        | 068.750 |
| /usr/lib/x86_64-linux-gnu/libselinux.so.1        | 166280         | 41         | 41        | 100.000 |
| /usr/lib/x86_64-linux-gnu/libdevmapper.so.1.02.1 | 438864         | 108        | 105       | 097.222 |
| /var/lib/docker/buildkit/cache.db                | 32768          | 8          | 5         | 062.500 |
| /usr/lib/x86_64-linux-gnu/libc.so.6              | 2216304        | 542        | 532       | 098.155 |
| /usr/lib/x86_64-linux-gnu/libsystemd.so.0.32.0   | 807936         | 198        | 190       | 095.960 |
| /usr/bin/dockerd                                 | 95731632       | 23372      | 16990     | 072.694 |
| /var/lib/docker/buildkit/containerdmeta.db       | 16384          | 4          | 4         | 100.000 |
| /usr/lib/x86_64-linux-gnu/libpcre2-8.so.0.10.4   | 613064         | 150        | 85        | 056.667 |
| /usr/lib/x86_64-linux-gnu/libm.so.6              | 940560         | 230        | 187       | 081.304 |
| /usr/lib/x86_64-linux-gnu/liblzma.so.5.2.5       | 170456         | 42         | 42        | 100.000 |
| /usr/lib/x86_64-linux-gnu/libcap.so.2.44         | 39024          | 10         | 10        | 100.000 |
| /usr/lib/x86_64-linux-gnu/liblz4.so.1.9.3        | 125152         | 31         | 31        | 100.000 |
| /var/lib/docker/buildkit/metadata_v2.db          | 16384          | 4          | 4         | 100.000 |
| /usr/lib/x86_64-linux-gnu/libgpg-error.so.0.32.1 | 149760         | 37         | 37        | 100.000 |
| /usr/lib/x86_64-linux-gnu/libgcrypt.so.20.3.4    | 1296312        | 317        | 114       | 035.962 |
| /usr/lib/x86_64-linux-gnu/libzstd.so.1.4.8       | 841808         | 206        | 163       | 079.126 |
| /usr/lib/x86_64-linux-gnu/libudev.so.1.7.2       | 166240         | 41         | 41        | 100.000 |
+--------------------------------------------------+----------------+------------+-----------+---------+
2.1.4 lsof
lsof -p 1099
COMMAND  PID USER   FD      TYPE             DEVICE SIZE/OFF       NODE NAME
dockerd 1099 root  cwd       DIR               8,18     4096          2 /
dockerd 1099 root  rtd       DIR               8,18     4096          2 /
dockerd 1099 root  txt       REG               8,18 95731632   17564073 /usr/bin/dockerd
dockerd 1099 root  mem-W     REG               8,18    32768   13250873 /var/lib/docker/buildkit/cache.db
dockerd 1099 root  mem-W     REG               8,18    16384   13250871 /var/lib/docker/buildkit/metadata_v2.db
dockerd 1099 root  mem-W     REG               8,18    16384   13250870 /var/lib/docker/buildkit/snapshots.db
dockerd 1099 root  mem-W     REG               8,18    16384   13250869 /var/lib/docker/buildkit/containerdmeta.db
dockerd 1099 root  mem       REG               8,18   309600   17564128 /usr/lib/x86_64-linux-gnu/libnss_systemd.so.2
dockerd 1099 root  mem-W     REG               8,18    65536   13250858 /var/lib/docker/volumes/metadata.db
dockerd 1099 root  mem       REG               8,18   613064   17569291 /usr/lib/x86_64-linux-gnu/libpcre2-8.so.0.10.4
dockerd 1099 root  mem       REG               8,18   149760   17570515 /usr/lib/x86_64-linux-gnu/libgpg-error.so.0.32.1
dockerd 1099 root  mem       REG               8,18   940560   17570772 /usr/lib/x86_64-linux-gnu/libm.so.6
dockerd 1099 root  mem       REG               8,18   166280   17571132 /usr/lib/x86_64-linux-gnu/libselinux.so.1
dockerd 1099 root  mem       REG               8,18  1296312   17570433 /usr/lib/x86_64-linux-gnu/libgcrypt.so.20.3.4
dockerd 1099 root  mem       REG               8,18   841808   17571483 /usr/lib/x86_64-linux-gnu/libzstd.so.1.4.8
dockerd 1099 root  mem       REG               8,18  2216304   17570121 /usr/lib/x86_64-linux-gnu/libc.so.6
dockerd 1099 root  mem       REG               8,18   166240   17564812 /usr/lib/x86_64-linux-gnu/libudev.so.1.7.2
dockerd 1099 root  mem       REG               8,18    39024   17564050 /usr/lib/x86_64-linux-gnu/libcap.so.2.44
dockerd 1099 root  mem       REG               8,18   125152   17570767 /usr/lib/x86_64-linux-gnu/liblz4.so.1.9.3
dockerd 1099 root  mem       REG               8,18   170456   17570769 /usr/lib/x86_64-linux-gnu/liblzma.so.5.2.5
dockerd 1099 root  mem       REG               8,18   438864   17570258 /usr/lib/x86_64-linux-gnu/libdevmapper.so.1.02.1
dockerd 1099 root  mem       REG               8,18   807936   17563757 /usr/lib/x86_64-linux-gnu/libsystemd.so.0.32.0
dockerd 1099 root  mem       REG               8,18   240936   17569784 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
dockerd 1099 root    0r      CHR                1,3      0t0          5 /dev/null
dockerd 1099 root    1u     unix 0xffff8b1548ec0c00      0t0      25224 type=STREAM
dockerd 1099 root    2u     unix 0xffff8b1548ec0c00      0t0      25224 type=STREAM
dockerd 1099 root    3u     unix 0xffff8b1551325400      0t0      25422 /var/run/docker/metrics.sock type=STREAM
dockerd 1099 root    4u     unix 0xffff8b1552019400      0t0      19442 /run/docker.sock type=STREAM
dockerd 1099 root    5u  a_inode               0,14        0       1049 [eventpoll]
dockerd 1099 root    6r     FIFO               0,13      0t0      28206 pipe
dockerd 1099 root    7w     FIFO               0,13      0t0      28206 pipe
dockerd 1099 root    8u     unix 0xffff8b1543359800      0t0      25423 type=STREAM
dockerd 1099 root    9u     unix 0xffff8b1547435c00      0t0      28373 type=STREAM
dockerd 1099 root   10uW     REG               8,18    65536   13250858 /var/lib/docker/volumes/metadata.db
dockerd 1099 root   11r      REG                0,4        0 4026531840 net
dockerd 1099 root   12u  netlink                         0t0      28473 ROUTE
dockerd 1099 root   13u  netlink                         0t0      28474 XFRM
dockerd 1099 root   14u  netlink                         0t0      28475 NETFILTER
dockerd 1099 root   15u     unix 0xffff8b1547434800      0t0      28605 /var/run/docker/libnetwork/fe50f8fc06f9.sock type=STREAM
dockerd 1099 root   16u     FIFO               0,24      0t0       1610 /run/docker/containerd/32d852ca2c732cc2017657530166bedb0d0e34eba9b7cd2eaa82484e4aef7b1d/init-stdout
dockerd 1099 root   17r     FIFO               0,24      0t0       1610 /run/docker/containerd/32d852ca2c732cc2017657530166bedb0d0e34eba9b7cd2eaa82484e4aef7b1d/init-stdout
dockerd 1099 root   18u     FIFO               0,24      0t0       1611 /run/docker/containerd/32d852ca2c732cc2017657530166bedb0d0e34eba9b7cd2eaa82484e4aef7b1d/init-stderr
dockerd 1099 root   19r     FIFO               0,24      0t0       1611 /run/docker/containerd/32d852ca2c732cc2017657530166bedb0d0e34eba9b7cd2eaa82484e4aef7b1d/init-stderr
dockerd 1099 root   20w      REG               8,18    18767   13762653 /var/lib/docker/containers/32d852ca2c732cc2017657530166bedb0d0e34eba9b7cd2eaa82484e4aef7b1d/32d852ca2c732cc2017657530166bedb0d0e34eba9b7cd2eaa82484e4aef7b1d-json.log
dockerd 1099 root   21u     FIFO               0,24      0t0       1615 /run/docker/containerd/c05b580cb355531b61b498476e6b5f61816fc5cfbf2fd74a174452f373fce8d7/init-stdout
dockerd 1099 root   22u     FIFO               0,24      0t0       1616 /run/docker/containerd/c05b580cb355531b61b498476e6b5f61816fc5cfbf2fd74a174452f373fce8d7/init-stderr
dockerd 1099 root   23r     FIFO               0,24      0t0       1615 /run/docker/containerd/c05b580cb355531b61b498476e6b5f61816fc5cfbf2fd74a174452f373fce8d7/init-stdout
dockerd 1099 root   24r     FIFO               0,24      0t0       1616 /run/docker/containerd/c05b580cb355531b61b498476e6b5f61816fc5cfbf2fd74a174452f373fce8d7/init-stderr
dockerd 1099 root   25w      REG               8,18   762036   13500701 /var/lib/docker/containers/c05b580cb355531b61b498476e6b5f61816fc5cfbf2fd74a174452f373fce8d7/c05b580cb355531b61b498476e6b5f61816fc5cfbf2fd74a174452f373fce8d7-json.log
dockerd 1099 root   26uW     REG               8,18    16384   13250869 /var/lib/docker/buildkit/containerdmeta.db
dockerd 1099 root   27uW     REG               8,18    16384   13250870 /var/lib/docker/buildkit/snapshots.db
dockerd 1099 root   28uW     REG               8,18    16384   13250871 /var/lib/docker/buildkit/metadata_v2.db
dockerd 1099 root   29u     sock                0,8      0t0      29001 protocol: NETLINK
dockerd 1099 root   30u     sock                0,8      0t0      29829 protocol: UDP
dockerd 1099 root   31u     sock                0,8      0t0      29003 protocol: UDP
dockerd 1099 root   32u     sock                0,8      0t0      31818 protocol: NETLINK
dockerd 1099 root   33u     sock                0,8      0t0      29004 protocol: TCP
dockerd 1099 root   34u     sock                0,8      0t0      29830 protocol: TCP
dockerd 1099 root   35uW     REG               8,18    32768   13250873 /var/lib/docker/buildkit/cache.db
dockerd 1099 root   38u     FIFO               0,24      0t0       1788 /run/docker/containerd/f3ac3845bcaea0baf810c4ffa89097d34f8dc851c949993c90719dbf2df8cdda/init-stdin
dockerd 1099 root   39u     FIFO               0,24      0t0       1789 /run/docker/containerd/f3ac3845bcaea0baf810c4ffa89097d34f8dc851c949993c90719dbf2df8cdda/init-stdout
dockerd 1099 root   40w     FIFO               0,24      0t0       1788 /run/docker/containerd/f3ac3845bcaea0baf810c4ffa89097d34f8dc851c949993c90719dbf2df8cdda/init-stdin
dockerd 1099 root   41w      REG               8,18      149   13788026 /var/lib/docker/containers/f3ac3845bcaea0baf810c4ffa89097d34f8dc851c949993c90719dbf2df8cdda/f3ac3845bcaea0baf810c4ffa89097d34f8dc851c949993c90719dbf2df8cdda-json.log
dockerd 1099 root   42r     FIFO               0,24      0t0       1789 /run/docker/containerd/f3ac3845bcaea0baf810c4ffa89097d34f8dc851c949993c90719dbf2df8cdda/init-stdout
dockerd 1099 root   46u     sock                0,8      0t0      35021 protocol: NETLINK

2.3 解决方案

除了在系统进程内存使用较大压力的情况下进行内存的回收外,我们也可以进行手动的·buffer/cache·回收,但由于·buffer/cache·主要是用于文件的读写使用,所以进行文件回收时,一般常伴随系统的IO飙高,因为系统内核也对比cache中的数据与硬盘中的数据是否一致,如果不一致需要写入,然后才能进行内存的回收;

$ sync
# 将内存中数据强制先刷新到磁盘中

清理Buffer缓存区域
$ 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分配器中的缓存对象

如果你必须清除磁盘高速缓存,第一个命令在企业和生产环境中是最安全,"...echo 1> ..."只会清除页面缓存。 在生产环境中不建议使用上面的第三个选项"...echo 3 > ..." ,除非你明确自己在做什么,因为它会清除缓存页目录项inodes

创建一个 shell 脚本,通过一个 cron 调度任务在每天下午2点自动清除RAM缓存。如下创建一个 shell 脚本 clearcache.sh 并在其中添加以下行:

 #!/bin/bash
 # 注意,我们这里使用了 "echo 3",但是不推荐使用在产品环境中,应该使用 echo 1
 echo 3 > /proc/sys/vm/drop_caches"

clearcache.sh文件设置执行权限

chmod 755 clearcache.sh

现在设置一个每天下午2点的定时任务来清除RAM缓存,打开crontab进行编辑。

crontab -e

添加以下行,保存并退出。

 0 3 * * * /root/shell_script/clear_cache.sh

参考文档:

  1. https://blog.youkuaiyun.com/imliuqun123/article/details/130149771
  2. https://huaweicloud.youkuaiyun.com/63566961d3efff3090b5e461.html?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Eactivity-1-125906007-blog-130149771.235%5Ev38%5Epc_relevant_anti_vip&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Eactivity-1-125906007-blog-130149771.235%5Ev38%5Epc_relevant_anti_vip&utm_relevant_index=2
<think> 嗯,用户现在在问Linux系统中大量内存cache占用的原因。我需要回顾之前对话历史中的引用内容,并整合相关知识来回答这个问题。 用户提供的引用内容很有帮助。引用[1]提到buff/cache主要用于dentry、Buffer Cache和Page Cache的缓存操作,这是提高文件读写效率的机制。引用[2]进一步解释Linux内存分配机制会优先使用物理内存作为缓存,即使程序关闭后这部分内存也不会立即释放,而是用作缓存。 引用[3]详细说明了dentry_cache的作用,它记录目录项到inode的映射关系,每次文件操作都可能创建新的缓存项。引用[4]和[5]则展示了实际案例,比如执行dd命令时会用大量内存作为磁盘数据缓存。 根据这些引用内容和Linux内存管理原理,cache占用大量内存的核心原因可以归纳为三点:首先,文件读写操作会让内核自动缓存数据到Page Cache;其次,频繁文件操作会积累dentry和inode缓存;最后,内核策略是尽可能利用空闲内存提升IO性能。 用户可能会混淆cache占用和高内存使用的关系,需要强调这是Linux设计的优化策略,不是内存泄漏。可用free命令的available字段说明可用内存的真实情况,这部分内容在之前的回答中也提到过。 </think> Linux系统中大量内存cache占用的核心原因在于其**基于性能优化的内存管理机制**,主要包含以下层次: --- ### 一、缓存机制的本质目的 Linux将空闲内存用作磁盘缓存(Page Cache/Buffer Cache),通过**预读机制**和**写缓冲策略**显著提升I/O性能: 1. **读取加速** 重复访问文件时直接从内存返回数据,减少磁盘寻道时间 $$ \text{访问延迟} \downarrow = \frac{\text{内存访问时间}}{\text{磁盘访问时间}} \approx \frac{100ns}{10ms} = 0.001\% $$ 2. **写入优化** 脏页(修改未落盘的数据)先缓存在内存,通过**pdflush线程**批量写入磁盘[^4] > 实验验证:连续读取1GB文件两次,第二次速度提升3-5倍[^1] --- ### 二、缓存类型与触发场景 | **缓存类型** | **作用** | **典型触发场景** | |---------------------|-----------------------------------|-------------------------------| | **Page Cache** | 缓存文件内容(4KB页) | `cat largefile.log` | | **Buffer Cache** | 缓存磁盘块数据(原始块设备) | `dd if=/dev/sda of=/dev/null` | | **dentry/inode** | 加速文件路径→inode转换 | `find / -name *.log` | | **Slab缓存** | 内核对象缓存(进程描述符等) | 高频创建/销毁进程 | > 案例:执行`find /`后dentry缓存暴增,再次执行速度提升10倍[^3] --- ### 三、内核的主动保留策略 1. **惰性回收机制** 当应用程序申请内存时,内核**优先分配free内存**而非立即回收缓存 ```mermaid graph LR A[应用申请内存] --> B{free内存 > 申请量?} B -->|是| C[直接分配] B -->|否| D[按LRU回收缓存] ``` 2. **水位控制模型** 内核通过`/proc/sys/vm/min_free_kbytes`设置内存警戒线,仅当低于阈值时才主动回收[^5] > 现象:关闭应用后其内存不会立即释放,而是转为缓存备用 --- ### 四、高性能场景的必然结果 1. **大数据处理** ```bash dd if=/dev/zero of=testfile bs=1G count=100 # 产生100GB缓存[^4] ``` 2. **数据库系统** MySQL的InnoDB缓冲池与Page Cache形成**双层缓存** 3. **频繁文件操作** 日志采集、编译构建等场景持续产生dentry缓存[^3] --- ### 内存状态解读技巧 通过`free -h`识别真实可用内存: ```bash total used free shared buff/cache available Mem: 62G 14G 300M 2.3G 48G 45G ``` 关键指标: ✅ **available** ≈ free + 可回收缓存 (此处45G为真实可用内存) ❌ 勿将**buff/cache**(48G)视为内存不足 > 当available接近0时才需干预[^2] --- ### 总结:设计哲学 Linux的缓存策略本质是**空间换时间**的权衡: $$ \text{性能增益} \propto \frac{\text{缓存命中率}}{\text{内存回收开销}} $$ 通过最大化利用空闲内存降低I/O瓶颈,符合服务器场景的优化目标[^2][^5]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值