生产环境JVM内存监控需分区域、盯变化、用对工具:堆内(新生代/老年代/元空间)与堆外(直接内存/线程栈/NMT)分开观测,结合jstat/jmap/jcmd、Arthas、Prometheus三层工具链,辅以GC日志、OOM转储等基线参数,实现问题快速归因。

生产环境中监控 JVM 内存结构,核心是分区域、盯变化、用对工具——不只看“用了多少”,而要看“谁在用、怎么涨、为何不回收”。堆内(新生代/老年代/元空间)和堆外(直接内存、线程栈、NMT 本地内存)必须分开观察,且每类指标需匹配对应手段。
盯住三类关键内存区域的动态
堆内存不能只看总使用率。重点监控以下三块:
-
新生代水位与行为:用
jstat -gc <pid> 1000观察 EU(Eden 使用率)、S0U/S1U(Survivor 使用量)。若 EU 每秒打满又清空但 YGC 频次飙升,说明对象创建过快;若 Survivor 区持续堆积、对象快速晋升到老年代,可能是-XX:MaxTenuringThreshold过小或 Survivor 空间不足。 -
老年代趋势是否健康:OU(Old Used)应呈周期性锯齿波动。若出现单向缓慢爬升、Full GC 后回落极少(如 980MB → 975MB),大概率存在内存泄漏。配合 GC 日志中
[Full GC (Metadata GC Threshold)]或[Full GC (Ergonomics)]可判断触发原因。 -
非堆内存不可忽视:Metaspace 持续增长提示类加载泄漏(如热部署、Groovy 脚本);Direct Memory 接近
-XX:MaxDirectMemorySize会引发 OOM;线程数随时间线性上升,往往意味着连接未释放或线程池未配置拒绝策略。
分层组合工具,兼顾实时性与归因能力
单一工具覆盖不了全场景,推荐三层搭配:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
基础层(命令行,零侵入):
jstat -gcutil <pid> 2s每2秒输出各区域使用率;jmap -histo:live <pid>快速列出存活对象类型及数量(重点关注 HashMap、ArrayList、ByteBuf、LogEvent 等高频泄漏点);jcmd <pid> VM.native_memory summary查看 NMT 统计(需启动时加-XX:NativeMemoryTracking=summary)。 -
可观测层(Arthas 实时诊断):运行
dashboard查整体内存与线程;用vmtool --action getInstances --className java.util.concurrent.ConcurrentHashMap --limit 10查特定集合实例数;执行heapdump --live /tmp/heap.hprof导出轻量快照,全程无需重启。 -
趋势层(Prometheus + Grafana):通过 Micrometer 暴露
jvm.memory.used、jvm.gc.pause、jvm.threads.live等指标,配置分级告警——例如 Metaspace 使用率 > 90% 持续3分钟触发 P2,线程数 > 1000 且10分钟内增长超200 触发 P1。
必须启用的日志与参数基线
监控不是事后补救,而是上线前就埋好线索:
立即学习“Java免费学习笔记(深入)”;
- GC 日志必加:
-Xloggc:/logs/gc-%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M; - OOM 自动转储:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/heap- -XX:ErrorFile=/logs/hs_err_%p.log; - JMX 远程可连:
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false(生产建议配认证); - 堆外内存追踪(可选但关键):
-XX:NativeMemoryTracking=summary,后续可用jcmd <pid> VM.native_memory summary查看。
从异常信号快速定位问题类型
看到某个现象,马上知道该查什么:
- 老年代缓慢上涨 + Full GC 后几乎不降 → 立即
jmap -dump:live,file=leak.hprof <pid>,用 MAT 看 Dominator Tree 和 Leak Suspects; - GC overhead limit exceeded → 表明 JVM 把 98% 时间花在 GC 却收效甚微,优先检查是否有大对象反复创建、日志异步队列积压或缓存未设上限;
- 线程数持续增长 + 大量 WAITING 状态集中在
java.util.concurrent.ThreadPoolExecutor.getTask→ 检查线程池是否配置了无界队列且任务执行慢; - Metaspace 使用率持续上升 → 执行
jcmd <pid> VM.class_hierarchy --loaded查已加载类数,结合jstat -class <pid>观察 loaded 类是否单向增长。

















