free -h 显示内存快满了是内存泄漏吗:一次 Linux 内存认知的复盘

一台 16G 内存的服务器跑着 Java 服务,free -h 一看 used 那列写着 15G,只剩 1G,我第一反应内存泄漏熬夜导堆分析,结果 Java 堆才 2G 很健康,所有进程内存加起来才 4G,中间那 10 多个 G 谁吃了。排查梳理:lsof 排除已删文件句柄,/proc/meminfo 看到 11G 在 Cached 页缓存,free -h 的 available 一列写着 13G 实际可用很充足;free -h 六列 total 总量、free 是完全没被碰过的内存(健康机器它本就很小不代表内存不够)、used 历史上常把缓存算进去虚高吓人别慌、buff/cache 是内核拿空闲内存做的可回收缓存、shared 共享内存、available 才是唯一该看的还能给新程序用多少;buff/cache 主要是页缓存内核把读过的磁盘文件顺手缓存在空闲内存里加速 IO,内核哲学是空闲内存等于浪费所以会用掉几乎所有空闲内存做缓存,跑久的 Linux buff/cache 大 free 小是健康表现,关键缓存内存可回收进程一要内存内核立刻丢缓存让座它不会饿死任何进程;判断内存够不够绝不能用 total 减 used 算剩余(used 混着可回收缓存会把健康机器误判成濒死),只看 available 这一列它是内核算好的扣除收不回部分后真正能立刻给新程序用的量,老系统读 /proc/meminfo 的 MemAvailable;真排查进程内存看 RSS 常驻内存不看 VSZ 虚拟空间,泄漏是趋势某进程 RSS 随时间持续只涨不降单看一时刻大不算泄漏;内存真不够的三个信号 available 持续逼近 0、vmstat 的 si so 频繁 swap 整机断崖变慢、OOM Killer 杀进程 dmesg 里 Killed process。正确做法是 free 的 used 大不要慌那多半是内核拿空闲内存做的可回收缓存,判断内存够不够只看 available,以及一套 Linux 内存排查纪律。

2021 年,一次"我盯着 free -h 那个用了 15G 的内存,熬了一整夜抓所谓的'内存泄漏',最后发现【根本没有泄漏】"的事故,把我对"内存被用掉了"这件事的理解,从头到尾翻新了一遍。那台服务器 16G 内存,上面跑着一个 Java 服务。某天我例行巡检,free -h 一看,used 那一列写着 15G——16G 的机器,用了 15G!我心里"咯噔"一下:内存快满了,这服务器随时要崩。我第一反应:Java 服务内存泄漏了。我立刻进入战备状态,导堆、看 GC 日志、分析对象引用……一整夜过去,Java 进程的堆,稳得像块石头,jmap 看到的堆用量才 2G 多,健康得很。可 free -h 那个 15G,纹丝不动地刺在那里。我开始怀疑是不是别的进程在吃,ps 把所有进程的内存加起来——所有进程的内存总和,也就 4G 出头。4G。可 free 说用了 15G。中间那 10 个多 G,被谁吃了?机器上每一个进程,我都查过了,它们加起来才 4G。free 口口声声说 15Gused 了——可这个系统里,我【找不到任何一个进程】对得上这笔账。这 10 个 G,既不在任何进程名下,又确确实实显示为"已用"——它到底【是什么】?如果它真被"用掉"了,为什么没有任何一个进程认领它?如果它没被"用掉",free 为什么把它算进 used?这件事逼着我把 free 的每一列、buff/cache 是什么、availablefree 的天壤之别,彻底理清了。本文复盘这次实战。

问题背景

环境:CentOS 7,16G 内存,跑一个 Java 服务
事故现象:
- free -h 看到 used 15G,16G 的机器只剩 1G
- ★ 以为内存泄漏,熬夜导堆分析 —— Java 堆才 2G,很健康
- ★ 所有进程内存加起来才 4G,那 10 多个 G 谁吃了?

现场排查:
# 1. ★ free -h 看到的(CentOS 7 的输出)
$ free -h
              total   used   free  shared  buff/cache  available
Mem:            16G    15G   320M    80M         11G        13G
#                      ^^^                       ^^^         ^^^
#                   ★ used 吓人          ★ 这两列才是关键

# 2. ★ 把所有进程的物理内存(RSS)加起来
$ ps aux --sort=-rss | awk 'NR>1{s+=$6}END{print s/1024/1024" GB"}'
4.2 GB                                  # ★★ 所有进程才 4.2G!

# 3. ★ 那 buff/cache 那 11G 是什么
$ cat /proc/meminfo | grep -E 'Cached|Buffers'
Buffers:        260000 kB
Cached:       11200000 kB                # ★★ 11G 在这:页缓存

# 4. ★ 这 11G,能不能被新程序拿去用
$ free -h | awk 'NR==2{print "available: "$7}'
available: 13G                           # ★★ 实际可用 13G!

根因(后来想清楚的):
1. ★ free 里的 used,在老版本/老观念里是个【极易
   误导】的数字。它把 buff/cache 算成了"已用"。
2. ★ 那 11G buff/cache,是【页缓存(page cache)】:
   内核把读过的磁盘文件内容,顺手缓存在空闲内存里,
   下次读同样的文件就不碰磁盘,直接命中内存。
3. ★ 关键:页缓存占的内存,是【可回收】的。一旦
   有进程真要内存,内核会【立刻把页缓存丢掉】,
   把这部分内存腾给进程 —— 它不是"被占死"的。
4. ★ 所以"内存够不够用",根本【不该看 used / free】,
   要看 ★ available —— 它 = free + 可回收的缓存,
   才是"还能给新程序用多少"的真相。本文 available
   是 13G,内存【健康得很】。
5. ★ 我熬夜抓的"泄漏",是个根本不存在的幽灵。那
   11G 不是被泄漏掉的,是内核【主动拿空闲内存做了
   缓存】—— 这是内核在帮你加速,是好事,不是病。
6. 真相:内存被 buff/cache "占着",和内存被
   "用掉了",是两件完全不同的事。空闲的内存不
   拿来做缓存,才是浪费。
不是内存泄漏,是我把"内核拿空闲内存做的缓存",
错看成了"被进程吃掉、回不来的内存"。

修复 1:free -h 每一列,到底是什么

# === ★ 先把 free 的每一列,逐个钉清楚 ===

# === ★ free -h 的输出(CentOS 7+ / 现代内核)===
$ free -h
#               total  used  free  shared  buff/cache  available
# Mem:            16G   15G  320M    80M         11G         13G
# Swap:          2.0G    0B  2.0G

# === ★ total:物理内存总量 ===
# 这台机器一共有多少内存。16G。没有歧义。

# === ★ free:★ "完全没被碰过"的内存 —— 易误解 ===
# ★ free 不是"可用内存"!它是"此刻【一点用途都没
#   派上】、纯粹空着的"内存。
# ★ 一台健康、运行已久的 Linux,free 通常都【很小】
#   (本文才 320M)—— 这【不是】问题。因为内核
#   会把暂时没人用的内存,统统拿去做缓存了。
# ★ ★ free 很小,绝不等于"内存不够"。

# === ★ used:★ 最容易吓人、最该警惕的一列 ===
# ★ 不同版本的 free,used 的算法不一样,历史上它
#   常常【把一部分缓存也算进去】,导致这个数虚高。
# ★ 看到 used 很大,★ 先别慌 —— 它不等于"进程
#   真正吃掉的内存"。

# === ★ buff/cache:内核拿空闲内存做的缓存 ===
# ★ 这部分内存,内核用它缓存了磁盘文件、文件系统
#   元数据。它【占着】内存,但【随时能还】。
# ★ 下一节专门讲它。

# === ★ shared:多个进程共享的内存(tmpfs 等)===
# 一般不大,先不深究。

# === ★★ available:★ 唯一该看的"还能用多少" ===
# ★ available = 当前 free 的 + buff/cache 里【可回收】
#   的那部分。它回答的是那个你真正关心的问题:
#   "现在再起一个程序,大概还有多少内存能给它?"
# ★ ★ 判断内存够不够,只看 available 这一列。

# === ★ 一句话记住该看哪 ===
# ★ free 列:别看,它小是正常的。
# ★ used 列:别慌,它大可能是缓存虚高。
# ★ ★ available 列:只看它。它才是真相。

# === 认知 ===
# ★ free -h 六列:total 总量;free 是"完全没被碰过"
#   的内存(健康机器它本就很小,不代表内存不够);
#   used 历史上常把缓存算进去,虚高吓人别慌;
#   buff/cache 是内核拿空闲内存做的可回收缓存;
#   ★ available 才是唯一该看的"还能给新程序用多少"。
#   判断内存够不够,只认 available 这一列。

修复 2:buff/cache——内核拿空闲内存做的缓存,是好事

# === ★ 把那"凭空消失的 10 多个 G",讲个明白 ===

# === ★ 页缓存(page cache)是什么 ===
# ★ 你的程序读一个磁盘文件,磁盘很慢。内核很聪明:
#   它把读过的文件内容,【顺手存一份在内存里】。
#   下次再读同一个文件,直接从内存命中,不碰磁盘。
# ★ 这份"内存里的文件副本",就是页缓存。free 里
#   buff/cache 那一大坨,绝大部分就是它。

# === ★ 关键认知:内核会用掉【几乎所有】空闲内存做缓存 ===
# ★ 内核的哲学是:★ "空闲的内存 = 被浪费的内存"。
#   一段内存,你不用它,它也只是空着、产生不了任何
#   价值。内核索性把暂时没进程用的内存,【全部】
#   拿去做页缓存,让磁盘 IO 快起来。
# ★ 所以一台跑了很久的 Linux,buff/cache 很大、
#   free 很小,是【绝对正常、且健康】的表现 ——
#   说明内核在尽职尽责地用内存帮你加速。

# === ★ 最关键的一点:缓存内存是"可回收"的 ===
# ★ buff/cache 占的内存,和进程吃掉的内存,有本质
#   区别:★ 它【随时可以被收回】。
# ★ 一旦有进程真的要内存、而 free 不够了,内核会
#   【立刻、自动】把页缓存丢掉一部分(那只是文件
#   副本,丢了大不了下次重新从磁盘读),把腾出来的
#   内存交给进程。这个过程,你完全感知不到。
# ★ 所以页缓存【不会】把进程"饿死"。它像一个
#   "临时占着工位、但你一来就立刻让座"的人。

# === ★ 亲手验证:缓存能被瞬间释放 ===
$ free -h | awk 'NR==2{print "回收前 buff/cache: "$6}'
# 回收前 buff/cache: 11G
$ sync && echo 3 > /proc/sys/vm/drop_caches   # ★ 手动丢弃所有缓存
$ free -h | awk 'NR==2{print "回收后 buff/cache: "$6}'
# 回收后 buff/cache: 300M               # ★★ 11G 缓存瞬间还回来了
# ★ 这证明:那 11G 从来没"丢",它一直是【可还的】。
# ★ ★ 注意:drop_caches 仅用于验证 / 排查,生产环境
#   【不要】常做 —— 丢了缓存,磁盘 IO 会暂时变慢。

# === ★ 所以本文那"消失的 10 个 G",真相是 ===
# ★ 它没消失,也没泄漏。它是内核拿"反正也空着"的
#   内存,做成了页缓存。它不在任何进程名下,因为它
#   【本就不属于任何进程】,它属于内核的缓存层。
# ★ 我那一夜,是在追一个内核的"功能",当成了"故障"。

# === 认知 ===
# ★ buff/cache 主要是页缓存:内核把读过的磁盘文件
#   顺手缓存在空闲内存里加速 IO。内核哲学是"空闲
#   内存=浪费",所以它会用掉几乎所有空闲内存做缓存
#   —— 跑久的 Linux buff/cache 大、free 小是健康表现。
#   ★ 关键:缓存内存可回收,进程一要内存内核立刻丢
#   缓存让座,它不会饿死任何进程。这是加速,不是病。

修复 3:available——唯一回答"内存够不够"的列

# === ★ 把"该看哪个数"这件事,一次说死 ===

# === ★ 错误的判断:16G - used = 剩余 ===
# ★ 本文我栽的根:我用 "total - used" 算剩余 ——
#   16G - 15G = 1G,我就以为"只剩 1G,要爆了"。
# ★ 这个算法【是错的】。因为 used 里混着可回收的
#   缓存,这 15G 里有 11G 是随时能还的缓存。
# ★ "total - used" 算出的"剩余",严重低估了真实
#   可用量,会把健康的机器误判成濒死。

# === ★ 正确的判断:只看 available ===
$ free -h
#               total  used  free  shared  buff/cache  available
# Mem:            16G   15G  320M    80M         11G         13G
#                                                            ^^^
# ★ available = 13G。它的含义是:"如果现在启动一个
#   新程序,在【不动用 swap、不发生卡顿】的前提下,
#   内核大约能立刻给它 13G。"
# ★ 这 13G 怎么来的:320M 的 free + buff/cache 里
#   大约 12.7G 可回收的部分。
# ★ ★ 13G 可用 / 16G 总量 —— 这台机器内存【非常健康】。

# === ★ 为什么是 available 而不是 free + buff/cache ===
# ★ buff/cache 里并非 100% 都能回收 —— 有一小部分
#   (如脏页、tmpfs、被锁定的页)收不回来。
# ★ available 是内核【自己算好】的"扣除了收不回的
#   部分之后,真正能拿出来的量"。所以直接信它,
#   别自己拿 free + buff/cache 去估。

# === ★ 老系统没有 available 列怎么办 ===
# ★ 很老的 free(procps 3.3.10 以前)没有 available
#   列,只有一行 "-/+ buffers/cache"。看那一行的
#   free 部分。或直接读 /proc/meminfo:
$ grep MemAvailable /proc/meminfo
MemAvailable:   13600000 kB             # ★ 这就是 available 的来源

# === ★ 一条简单的健康判断线 ===
# ★ available / total 还有 20% 以上 -> 内存健康。
# ★ available 持续走低、逼近 0 -> 才是真要担心,
#   这时再去查是哪个进程在涨(见修复 4)。
# ★ ★ used 多大、free 多小,都【不是】判断依据。

# === 认知 ===
# ★ 判断内存够不够,★ 绝不能用 total-used 算剩余
#   (used 混着可回收缓存,会把健康机器误判成濒死)。
#   只看 available 这一列 —— 它是内核算好的、扣除了
#   收不回部分之后真正能立刻给新程序用的量。老系统
#   读 /proc/meminfo 的 MemAvailable。available 占
#   total 20% 以上即健康,持续逼近 0 才需担心。

修复 4:真要排查内存,该看进程的什么

# === ★ 如果 available 真的低了,这样查进程 ===

# === ★ 第一步:按物理内存排序,揪出吃内存大户 ===
$ ps aux --sort=-rss | head
# USER  PID  %CPU %MEM    VSZ     RSS  ...  COMMAND
# ★ 看 RSS 那一列,从大到小。最上面的就是嫌疑人。

# === ★ 关键区分:VSZ 和 RSS 是两回事 ===
# ★ VSZ(虚拟内存大小):进程【申请 / 映射】了多大
#   的虚拟地址空间。它包含了很多【还没真正用到、
#   没占物理内存】的部分。VSZ 经常大得吓人,★ 它
#   【不是】进程真实占的内存,排查时基本可以忽略。
# ★ ★ RSS(常驻内存):进程【真正占用的物理内存】。
#   这才是它实打实吃掉的、要算账的内存。
# ★ 排查内存,★ 只看 RSS,别被 VSZ 吓到。

# === ★ 第二步:盯一个进程,看它的 RSS 是否持续涨 ===
# ★ "内存泄漏"的真正定义:一个进程的 RSS,【随时间
#   持续单调上涨,只涨不降】。
$ while true; do
    ps -o rss= -p 12345 | awk '{print strftime("%H:%M:%S"),$1/1024" MB"}'
    sleep 60
  done
# ★ 连续观察:RSS 一直涨不回头 -> 真泄漏;
#   涨涨跌跌、稳定在一个范围 -> 正常,不是泄漏。
# ★ ★ 单看一个时刻的 RSS 大,不能叫泄漏 —— 泄漏是
#   "趋势",必须看一段时间。

# === ★ 第三步:看一个进程内存的细致构成 ===
$ cat /proc/12345/status | grep -E 'VmRSS|VmSwap'
# VmRSS:   2100000 kB                   # 物理内存
# VmSwap:    50000 kB                   # 被换到 swap 的部分
$ pmap -x 12345 | tail -1               # 更细的内存映射汇总

# === ★ 第四步:Java 等带虚拟机的,还要看它自己的内存 ===
# ★ Java 进程的 RSS,= JVM 堆 + 元空间 + 线程栈 +
#   堆外内存 + JVM 自身。光看 RSS 大,不知道大在哪。
$ jcmd 12345 GC.heap_info                # 看 JVM 堆
$ jcmd 12345 VM.native_memory summary    # 看 native 内存(需开 NMT)
# ★ Java RSS 涨,可能是堆,也可能是堆外 / 元空间 /
#   线程过多 —— 要进一步分。

# === 认知 ===
# ★ available 真的低了才查进程:ps aux --sort=-rss
#   揪大户。★ 区分 VSZ(申请的虚拟空间,虚高,忽略)
#   和 RSS(真占的物理内存,只看它)。"泄漏"的定义
#   是某进程 RSS 随时间持续只涨不降 —— 必须连续观察
#   一段时间看趋势,单看一时刻 RSS 大不算泄漏。Java
#   等还要用 jcmd 进一步分堆 / 堆外 / 元空间。

修复 5:内存真不够时,系统会有什么表现

# === ★ 内存真到危险线,系统会怎样,怎么识别 ===

# === ★ 信号 1:available 持续走低,逼近 0 ===
# ★ 这是最早的预警。光 used 大不算,available 一路
#   下滑、收不住,才是真的在恶化。

# === ★ 信号 2:开始大量用 swap ===
# ★ free 不够,内核会把一部分【不常用】的内存页,
#   写到磁盘上的 swap 分区,腾出物理内存。
$ free -h                              # 看 Swap 行的 used
$ vmstat 1                             # ★ 看 si / so 两列
#  si = swap in(从 swap 读回),so = swap out(换出)
# ★ si / so 持续 > 0,而且数值不小 -> 系统在频繁
#   swap,内存吃紧了。★ swap 走磁盘,极慢,一旦
#   频繁 swap,整机性能会断崖式下跌。

# === ★ 信号 3:★ OOM Killer 出手杀进程 ===
# ★ 内存真的山穷水尽(swap 也满了),内核会启动
#   OOM Killer(Out Of Memory 杀手):它【挑一个
#   进程,直接杀掉】,强行腾内存,保住整个系统。
# ★ 被杀的进程,会"莫名其妙"地消失。怎么确认是
#   OOM Killer 干的:
$ dmesg | grep -i 'killed process'
# Out of memory: Killed process 12345 (java) ...
$ dmesg | grep -i 'oom'
# ★ 看到这种,就是内存真的爆了,OOM Killer 杀了人。

# === ★ OOM Killer 挑谁杀 ===
# ★ 它按一个 oom_score 打分,大致是"占内存越多、
#   越该死"。所以最吃内存的那个(往往就是你的主
#   服务),最容易被它选中 —— 这很讽刺但合理。
$ cat /proc/12345/oom_score             # 看某进程的 oom 评分

# === ★ 对比:本文事故,以上信号一个都没有 ===
# ★ available 13G,健康;swap used 0,没碰 swap;
#   dmesg 里没有任何 oom 记录。
# ★ ★ 三个真·危险信号全是阴性 —— 这本身就足以证明:
#   内存【根本没问题】。我那一夜的恐慌,毫无根据。
# ★ 教训:判断内存有没有事,看的是 available、swap
#   活动、oom 日志这三样,【不是】free 里的 used。

# === 认知 ===
# ★ 内存真不够的三个信号:① available 持续走低逼近
#   0;② 频繁 swap(vmstat 的 si/so 持续 >0,整机
#   会断崖变慢);③ ★ OOM Killer 杀进程(dmesg 里
#   "Killed process",它挑占内存最多的杀)。判断内存
#   有没有事,认这三样 —— 本文这三项全阴性,证明内存
#   健康,used 大纯粹是缓存虚高。

修复 6:Linux 内存排查纪律

# === 这次事故暴露的认知盲区,定几条纪律 ===

# === 1. ★ 判断内存够不够,只看 free 的 available 列,不看 used / free ===
$ free -h

# === 2. ★ used 大不等于内存紧张,它常把可回收缓存算进去虚高 ===

# === 3. ★ free 列小是健康机器的正常表现,内核会用掉几乎所有空闲内存做缓存 ===

# === 4. ★ buff/cache 是页缓存,可回收,进程要内存内核会立刻丢缓存让座 ===

# === 5. 验证缓存可回收:sync; echo 3 > drop_caches(★ 仅排查用,别在生产常做)===

# === 6. ★ 排查进程内存看 RSS 不看 VSZ,VSZ 是虚拟空间虚高 ===
$ ps aux --sort=-rss | head

# === 7. ★ 泄漏是趋势:RSS 随时间持续只涨不降,单看一时刻大不算泄漏 ===

# === 8. 内存真危险的信号:available 逼近 0、频繁 swap、dmesg 有 oom ===
$ vmstat 1 ; dmesg | grep -i oom

# === 9. OOM Killer 会挑占内存最多的进程杀,被杀进程会莫名消失,查 dmesg 确认 ===

# === 10. 排查"内存是不是有问题"的步骤链 ===
$ free -h                            # ① 看 available,不是 used
$ vmstat 1                           # ② 看 si/so 有没有频繁 swap
$ dmesg | grep -i 'killed process'   # ③ 有没有 OOM 杀进程
$ ps aux --sort=-rss | head          # ④ available 真低了才查进程 RSS
# available 充足 + 无 swap + 无 oom = 内存健康,used 大是缓存,别瞎查。

命令速查

需求                        命令
=============================================================
看内存概况                  free -h
★ 看真正可用内存            free -h 的 available 列
看可用内存(底层)          grep MemAvailable /proc/meminfo
看缓存构成                  grep -E 'Cached|Buffers' /proc/meminfo
按物理内存排序进程          ps aux --sort=-rss | head
看某进程真实内存            cat /proc/PID/status | grep VmRSS
看 swap 活动                vmstat 1(看 si / so 列)
看是否发生过 OOM            dmesg | grep -i 'killed process'
看某进程 OOM 评分           cat /proc/PID/oom_score
手动丢弃缓存(★ 仅排查)    sync && echo 3 > /proc/sys/vm/drop_caches

口诀:free 的 used 大不要慌 那多半是内核拿空闲内存做的可回收缓存
      判断内存够不够只看 available,真危险才有 swap 飙升和 OOM 杀进程

避坑清单

  1. 判断内存够不够只看 free 的 available 列,不要看 used 也不要用 total 减 used 算剩余
  2. free 里的 used 历史上常把可回收缓存算进去会虚高吓人,used 大不等于内存紧张
  3. free 列小是健康机器的正常表现,内核会主动用掉几乎所有空闲内存做页缓存加速 IO
  4. buff/cache 主要是页缓存,它占着内存但随时可回收,进程一要内存内核立刻丢缓存让座
  5. 缓存内存不会饿死任何进程,空闲内存不拿来做缓存才是浪费,这是内核加速不是故障
  6. 排查进程内存看 RSS 常驻内存,不看 VSZ 虚拟空间,VSZ 包含没真正用到的部分会虚高
  7. 内存泄漏是趋势:某进程 RSS 随时间持续单调只涨不降,单看一个时刻 RSS 大不能叫泄漏
  8. 内存真危险的信号是 available 持续逼近 0、vmstat 的 si so 频繁大于 0、dmesg 有 oom 记录
  9. OOM Killer 内存山穷水尽时会挑占内存最多的进程直接杀掉,进程莫名消失查 dmesg 确认
  10. drop_caches 手动丢缓存只用于验证排查,生产环境别常做,丢了缓存磁盘 IO 会暂时变慢

总结

这次"熬一整夜抓一个不存在的内存泄漏"的事故,纠正了我一个关于"占用"的、藏得极深的错觉。在我过去的脑子里,内存的状态,只有【非黑即白】的两种:一种叫"空闲",意思是"没人要、随便用";另一种叫"已用",意思是"被占走了、回不来了"。在我这套二分法里,free -h 那个 used: 15G,意思板上钉钉——有 15G 内存,落进了"已用"这个黑洞,被某个东西【拿走且不归还】了。剩下的事顺理成章:既然 15G 被"拿走不还",那一定有个进程在偷偷吞噬,这就是"泄漏"。我那一整夜的导堆、看 GC、查引用,全部建立在这个二分法之上。可天亮时我对上的那笔账,把这套二分法砸得粉碎:所有进程的内存加起来才 4G,而 used 说 15G——中间整整 11G,既不"空闲"(free 把它算进了 used),又不被任何进程"已用"(没有一个进程认领它)。它卡在我那套黑白二分法【根本没有的第三个格子】里。我被逼着去面对它,才终于看清:内存的状态,从来不是两种,是【三种】。除了"空着的"和"被进程占死的",还有第三种,也是健康 Linux 上占比最大的一种——"被内核拿去做缓存、但你一要就立刻还你的"。这第三种内存,它【占用着】,却没有【被用掉】。"占用"和"用掉",这两个我一直当成同义词的词,在这里裂开成了天差地别的两件事。页缓存就站在这道裂缝上:它实实在在地占着那 11G,所以 free 不肯把它算作空闲;但它又随时准备让座,所以它对任何一个真正需要内存的进程来说,等于不存在。它是一个"占着座位、却随叫随到地起身"的人——你说他占了座吗?占了。你说这座位你坐不了吗?你随时能坐。复盘到根上我才明白,我那一夜的恐慌,根源不是技术不熟,而是我脑子里那把尺子,刻度太少。我只有"有"和"无"两格,于是我被迫把一切"看起来被占着"的东西,都塞进"无"那一格,然后为这个虚构的"无"惊慌失措。这次最大的收获,是我学会了对一切"占用类"的数字,多问一个问题:它是被【占死了】,还是只是被【暂用着】?这个区别,几乎无处不在。一个连接池显示"占用 80 个连接",这 80 个是真有 80 个请求在跑,还是大多是空闲待命、随时能复用的?一块磁盘"用了 90%",这 90% 是不可删的核心数据,还是一半都是能随时清的缓存和日志?一个线程池"满了",是真有那么多活在干,还是线程只是占着没退?这些数字,几乎全都和内存一样,藏着那个"被占用但可回收"的第三态。而绝大多数监控、绝大多数人的直觉,都只给你"用了多少"这一个数——它最大、最显眼、也最会骗人。真正该追问的,永远是另一个数:在不伤害任何人的前提下,你现在【还能拿出来多少】?对内存,这个数叫 available。我熬那一夜,不是因为我看错了一个数字,是因为我从没想过,我该看的【根本是另一个数字】。从此我对任何一个"占用率"都会留个心眼:先别急着为那个高高的"已用"心跳加速,先找一找,有没有一个安安静静的、叫"可用"的数——那个数,才是系统真正想对我说的话。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
Linux教程

SSH 报 REMOTE HOST IDENTIFICATION HAS CHANGED:一次主机密钥与中间人警告的复盘

2026-5-21 1:15:48

Linux教程

kill -9 杀不掉的进程:一次僵尸进程与父进程收尸的复盘

2026-5-21 1:26:22

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索