"占用大量内存"和"内存泄漏"是两个不同的问题。泄漏是指进程的 RSS 持续上升、从不下降,即使机器处于空闲状态也是如此。单次快照看不出这一点——需要间隔一段时间取两次快照。
1. 现在谁占用的内存最多
$ clai 按内存使用量列出进程→ ps -eo pid,comm,rss,%mem --sort=-rss | head -4 PID COMMAND RSS %MEM 218979 firefox 2089376 3.1 269458 verba 1257196 1.9 727108 telegram 1249824 1.9
RSS 以 KB 为单位,是真正重要的数字:实际占用的物理内存。这只是嫌疑名单,不是答案。
2. 随时间观察单个进程
$ clai 每 10 秒采样一次 pid 269458 的内存,共 6 次→ pidstat -r -p 269458 10 6
这才是真正的测试。负载平稳的情况下,六次采样都在上升就是泄漏。上升后趋于平稳则是缓存在填充,属于正常现象,会自行停止。
3. 不装额外软件包的低成本采样
$ clai 把这个进程的内存每分钟记录到文件→ while sleep 60; do printf '%s %s\n' "$(date +%T)" "$(grep VmRSS /proc/269458/status)"; done | tee mem.logVmRSS: 1257196 kB
pidstat 属于 sysstat 软件包,不一定已安装。/proc/<pid>/status 则始终存在。让它跑上一小时,答案的走势就会一目了然。
4. 内存具体去了进程的哪里
$ clai 显示 pid 269458 的内存映射,按大小排序→ sudo pmap -x 269458 | sort -k3 -rn | head
如果某个匿名映射在两次 pmap 运行之间不断增大,那就是堆。大量不断增多的小映射通常意味着线程栈泄漏或未关闭的 mmap 文件。
5. 先排除文件缓存
$ clai 显示不含缓存和缓冲区的内存使用情况→ free -h total used free shared buff/cache availableMem: 62Gi 18Gi 2.1Gi 1.2Gi 42Gi 43Gi
要看 available,不是 free。Linux 会故意用页面缓存填满空闲内存,并按需释放。"只剩 2 GB 空闲"而 available 有 43 GB,这是健康的系统,不是泄漏。
6. 确认问题出在进程而非整机
$ clai 检查内核是否因内存不足杀掉过进程→ sudo dmesg -T | grep -i 'killed process'
如果 OOM killer 触发过,内核会记录它选中的进程以及当时的内存占用。这是你能拿到的最有力的证据,而且已经替你写好了。
常见误区
- RSS 会重复计算共享内存。 两个共享同一库的进程都会各自报告那些页面。要得到每个进程的真实数字,使用
smem或/proc/<pid>/smaps_rollup里的 PSS。 - 重启只是权宜之计,不是诊断。 它会清空曲线、抹去证据。先采样,再重启。
- 容器限制在容器内部看不到。 容器里的进程通过
free看到的是宿主机的总内存;真正的上限记在/sys/fs/cgroup/memory.max里。
相关问题
多大的增长算泄漏? 只要在负载平稳时持续向上就算。一个每小时多占 50 MB 且从不释放的进程,无论加多少内存,迟早都会触发 OOM killer。
Linux 上内存占用高本身是坏事吗? 不算。闲置的内存就是浪费的内存——内核会用它做缓存,并在有压力时回收。应该关注的是 available 和交换分区的活动情况。
用什么工具能找到具体泄漏的代码行? C/C++ 用 Valgrind(--leak-check=full),其他语言用各自的堆分析器。这里的命令能找到是哪个进程;修复它要用别的工具。
另请参阅
告诉 CliAI 你想测量什么,它会写出你原本要去查的 pidstat 调用。一行命令安装。