free命令不能定位java内存泄漏,但可识别异常:重点关注mem行available是否持续萎缩、swap行used是否缓慢增长,并结合ps、jstat等交叉验证堆外泄漏。

free 命令本身不能定位 Java 内存泄漏,它只提供系统级内存快照,但能帮你快速识别“是否真有异常”以及“该往哪个方向查”。关键不是盯着 used,而是看 available 是否持续萎缩、swap used 是否缓慢增长,并结合 Java 进程行为交叉判断。
看懂 free 输出里真正重要的三列
执行 free -m 或 free -h,重点关注:
- Mem 行的 available:这是最该盯的数字。它代表当前可立即分配给新进程、且不影响性能的内存估算值(已扣除不可回收 slab、脏页等)。Java 应用正常运行时,只要 available 还剩总内存的 5% 以上(比如 16G 机器剩 800M+),通常不构成瓶颈。
- Swap 行的 used:如果这个值从 0 开始缓慢爬升(不是突增),尤其在 Java 进程启动后几小时内持续上涨,很可能是 JVM 堆外内存泄漏(如 DirectByteBuffer、Netty native memory、JNI 调用未释放)或内核模块吃内存。
- buff/cache 列不必恐慌:它高说明系统在高效利用空闲内存做缓存。只要 available 不掉,就不是泄漏信号;若 available 极低而 buff/cache 又极高,才需怀疑脏页积压或 tmpfs 占用(如 /dev/shm)。
发现异常后,用 free 锁定时间趋势
单次执行 free 没意义,要观察变化。推荐用循环记录关键字段:
while true; do echo "$(date '+%F %T') $(free | awk 'NR==2{print ,}')"; sleep 5; done >> /tmp/java_mem_trend.log
之后用 awk '{print $3}' /tmp/java_mem_trend.log | sort -n | tail -5 查看 used 是否线性增长,或 awk '{print $4}' /tmp/java_mem_trend.log | sort -n | head -5 看 available 是否单向下降。如果变化节奏和某个 Java 服务启停高度同步,就基本圈定了嫌疑范围。
交叉验证:从系统到 JVM 进程逐层下钻
free 提示异常 ≠ Java 堆泄漏,必须排除其他可能:
- 先用 ps aux --sort=-%mem | head -10 或 top(按 Shift+M)确认是不是 Java 进程 RES(常驻内存)在涨。注意区分:RES 高但堆不大 → 很可能是堆外泄漏;jstat 显示老年代稳定但 RES 持续涨 → 几乎可以确定是堆外问题。
- 检查是否为共享内存占用:运行 df -h -t tmpfs,看 /dev/shm 是否被 Java NIO 或某些中间件大量写入;再查 cat /proc/meminfo | grep Shmem,Shmem 值偏高(几百 MB+)就是线索。
- 排查内核态吃内存:如果所有 Java 进程 RSS 总和远小于 free 显示的 used,运行 slabtop -o(按 c 排序),重点关注 kmalloc-*、dentry、inode_cache 等 cache 的 #use 和 Obj/kB 比值——若对象数量大但单个极小,容易被高频小分配打满。
针对 Java 堆外泄漏的轻量确认方法
如果怀疑是 DirectByteBuffer 或 Netty native memory,不用立刻上 jemalloc 或 Native Memory Tracking(NMT),先快速验证:
- 加 JVM 参数重启应用:-XX:NativeMemoryTracking=summary -XX:+UnlockDiagnosticVMOptions,然后用 jcmd
VM.native_memory summary 查看 total 和 internal 分类是否随时间增长。 - 观察 /proc/
/smaps_rollup 中的 MMUPageSize 和 MMUPageSize=4k 对应的 anon-rss 增长趋势,比单纯看 RSS 更准。 - 用 pmap -x
看是否有大量 64MB 或 128MB 的匿名映射段(常见于 Netty PooledByteBufAllocator 的 arena)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











