Linux内存被缓存吃满:buff/cache该不该手动释放

    发布时间:2026-09-17 04:30 更新时间:2026-09-17 04:30 阅读量:0

    不少站长第一次在服务器上敲下 free -h,看到 buff/cache 那一栏的数字比 used 还大,心里立刻一紧:内存是不是被吃光了?要不要赶紧释放一下?于是上网搜到一条命令,往 /proc/sys/vm/drop_caches 里写个 3,缓存数字瞬间掉下来,感觉服务器“清爽”了。过一阵子缓存又涨回去,于是怀疑是不是有程序在泄漏内存。这个循环其实建立在两个误解之上:一是把 buff/cache 当成被占用的内存,二是把“内存占用高”直接等同于“内存泄漏”。这篇文章把这两件事说清楚,再给出真正该看的指标和该做的事。

    buff/cache 到底是什么:内核主动借用的空闲内存

    Linux 的内存管理有一条基本原则:空闲的内存是浪费的内存。只要物理内存还有富余,内核就会把磁盘上读过的数据留在页缓存(page cache)里,把写操作先攒在缓冲区(buffer)里,等合适时机再刷盘。这样下次读同一批文件时直接命中内存,不必再去碰磁盘。free 命令里的 buff/cache 就是这类缓存的总和,它属于“可以被立刻回收”的内存,不归任何进程所有,也不是进程泄漏出来的。

    正因为可以随时回收,内核在给新进程分配内存时,会优先从 buff/cache 里拿,不够再考虑换出匿名页。所以缓存高并不妨碍你启动程序,它只是让磁盘 IO 变快。真正要看的是 available 这一列:它表示在不使用 swap 的前提下,系统大约还能拿出多少内存给新应用。只要 available 还有余量,buff/cache 高就是健康的,甚至是好事。

    判断内存是否吃紧,用下面这组命令比盯着 buff/cache 有用得多:

    free -h
    

    关注 available,而不是 buff/cache

    cat /proc/meminfo | grep -E 'MemAvailable|MemFree|Cached|Dirty|SwapCached'

    看谁在真正吃内存(按 RSS 排序)

    ps -eo pid,comm,rss --sort=-rss | head -n 15

    看 swap 是否被大量使用,以及换入换出频率

    vmstat 1 5

    其中 vmstat 的 si/so 两列很关键:如果长期为 0 或接近 0,说明系统没有发生明显的换页压力,内存是够用的;如果 si/so 持续偏大,同时 available 很低,那才是真的紧张,需要从应用侧找原因,而不是去清缓存。ps 按 RSS 排序则能帮你定位是哪个进程占了大头,比如数据库的 buffer pool、Java 堆、PHP-FPM 进程数等。

    手动 drop_caches 的代价:清缓存不等于解决问题

    内核确实提供了手动回收缓存的入口,但它是一个调试/应急接口,不是日常运维手段:

    # 先同步脏页,避免丢失待写入数据
    sync
    
    

    1=回收页缓存,2=回收可回收 slab,3=两者都回收

    echo 3 > /proc/sys/vm/drop_caches

    执行之后你会发现 buff/cache 大幅下降,但接下来一段时间磁盘 IO 会明显变忙,因为之前被缓存的文件都要重新从磁盘读。对跑着数据库、Web 服务的机器来说,这等于主动把性能优势丢掉,还可能引发短时间的响应抖动。更关键的是,它只改变了数字,不改变根因:如果是应用本身内存分配有问题,缓存清掉之后它照样会把内存吃回去。

    drop_caches 真正合适的场景很少,大致是:做基准测试前希望每次从磁盘冷读、排查某些缓存相关的疑难问题时做对照实验。生产环境不建议写成定时任务,也不建议因为监控面板上 buff/cache 高就自动触发。

    另外要注意,free 里的 used 不含 buff/cache,但很多云厂商的监控面板会把“已用内存”算成 total - free,把缓存也记进去,于是曲线常年贴着 90% 以上。遇到这种情况,先确认监控项的口径,再决定要不要处理,别被一条曲线牵着走。

    判断是否真的内存不足:看 available、swap 与 OOM

    与其纠结缓存,不如盯住几个真正说明问题的信号。第一是 available 长期偏低,比如只剩几百 MB 且持续下降;第二是 swap 使用量持续增长,同时 vmstat 里 si/so 不为零;第三是 dmesg 里出现 OOM Killer 记录,说明系统已经在杀进程自保。可以用下面的方式确认:

    # 是否有进程被 OOM Killer 干掉
    dmesg -T | grep -i -E 'oom|killed process'
    
    

    观察一段时间内的 available 与 swap

    free -m -s 5

    查看某个进程的详细内存构成

    cat /proc/<PID>/status | grep -E 'VmRSS|VmSwap|VmSize'

    如果确实内存吃紧,处理顺序一般是:先确认是不是配置给大了,比如 JVM 的 -Xmx、MySQL 的 innodb_buffer_pool_size、PHP-FPM 的 pm.max_children,这些参数累加超过物理内存是很常见的原因;再看是否有进程异常增长(用 ps 或 top 对比前后 RSS)、是否有连接数暴涨、是否有大文件被一次性读入内存;最后才是考虑加内存或加 swap 作为兜底。swap 不是洪水猛兽,小内存机器留一点 swap 反而能避免被 OOM 直接干掉,但前提是磁盘 IO 扛得住。

    还有一类容易误判的情况:容器里看到的 free 是宿主机视角,容器自身的内存限制由 cgroup 控制,此时应该看 /sys/fs/cgroup/memory/ 下的 memory.usage_in_bytes 与 memory.limit_in_bytes(cgroup v2 路径为 memory.current 和 memory.max),而不是宿主机 free 的数字,具体以实际发行版和内核版本为准。

    小结:让缓存干活,把注意力放回应用

    buff/cache 高是 Linux 在正常利用空闲内存,它随时可回收,不影响新程序申请内存;真正要盯的是 available、swap 活动量和有没有 OOM 记录。drop_caches 只在做冷读测试、排查缓存相关疑难时偶尔一用,日常别把它当清理工具,更别写进定时任务。

    下一步建议很简单:把监控告警从“内存使用率”改成“available 低于阈值”或“发生 OOM”,再顺手核对一遍数据库、JVM、PHP-FPM 的内存参数之和是否超过物理内存。把这些理顺之后,你会发现那条常年 90% 的内存曲线,其实一直是服务器在认真干活。

    继续阅读

    📑 📅
    服务器时间不同步导致证书与定时任务异常:NTP/chrony 校时配置与排查 2026-09-16
    PostgreSQL 连接数与内存调优:max_connections 与 shared_buffers 怎么配 2026-09-16
    Linux文件句柄耗尽排查:Too many open files 从ulimit到systemd 2026-09-16
    Nginx 后端真实 IP 获取:X-Forwarded-For 与 real_ip 配置 2026-09-16
    rsync 增量同步与断点续传实战:exclude、--delete 与限速 2026-09-16
    SSH 连接频繁断开与卡顿排查:心跳、MTU 与 DNS 反解 2026-09-17
    MySQL表空间与ibdata1膨胀处理:独立表空间、碎片整理与磁盘回收 2026-09-17
    系统盘满了却找不到大文件:被删除但仍被进程占用的句柄排查与恢复空间 2026-09-17
    服务器 swap 使用率飙升:正常换页还是内存真不够用 2026-09-17
    Docker容器时区不对?TZ变量与localtime挂载的正确用法 2026-09-17