JVM监控内存是保障Java应用稳定性的核心手段,直接决定系统能否扛住高并发和避免内存泄漏。 很多开发者把目光放在CPU和接口响应上,但内存一旦失控,GC频繁甚至OOM,整个服务就会陷入瘫痪,下面从指标、工具、排查到选型,一次性讲透JVM监控内存该怎么做。
JVM监控内存到底在监控什么?
堆内存、元空间、线程栈、直接内存,这几块是JVM内存监控的核心区域,很多人只盯着堆内存使用率,其实非堆区域出问题同样致命。
堆内存:GC频率和对象分布
– 新生代(Eden、Survivor)和老年代的使用比例,直接反映对象生命周期。
– 当老年代占用持续攀升且Full GC无法回收,说明存在内存泄漏或对象晋升过快。
– 监控指标:堆内存使用量、GC次数、GC停顿时间、各代晋升速率。
元空间(Metaspace):类加载泄漏的重灾区
– 元空间不再受-XX:MaxPermSize限制,但占用过多会导致FGC甚至OOM。
– 如果出现Metaspace OOM,多半是类加载器未卸载或框架动态生成类过多(如CGLIB、反射)。
– 监控指标:已加载类数量、元空间使用量、类卸载频率。
线程栈与直接内存:容易被忽略的角落
– 线程栈:每个线程占用的栈内存,线程数过多时占用可观,还可能引发OutOfMemoryError:unable to create new native thread。
– 直接内存:通过ByteBuffer.allocateDirect分配,不归GC管理,一旦泄漏只能通过操作系统层面监控发现。
– 监控指标:线程数、活跃线程、直接内存使用量(通过JMX或pmap辅助)。
JVM监控内存常用命令:jstat、jmap、jcmd实战
命令行工具是排查内存问题的第一选择,特别是线上环境不方便装Agent时,下面这些命令你最好背下来。
jstat:实时查看GC和堆内存
– 查看堆内存使用率:jstat -gcutil ,输出S0、S1、E、O、M、CCS等百分比,轻松识别老年代是否持续增长。
– 查看GC统计:
jstat -gc
– 如果Old区占用超过90%且一直不降,基本可以判断内存压力大或有泄漏。
jmap:堆转储与分析
– 获取堆转储文件:jmap -dump:live,format=b,file=heap.hprof ,live只保留存活对象,文件更小。
- 打印堆直方图:jmap -histo:live ,快速看到占用最多的对象类型。
- 注意:jmap在生产环境可能触发Full GC,建议在低峰期执行或使用jcmd替代。
jcmd:多功能瑞士军刀
- 查看VM参数:jcmd ,确认堆大小、GC收集器等配置。
- 查看系统属性:jcmd ,排查环境变量问题。
- 生成堆转储:jcmd
JVM监控内存泄漏排查:从现象到根因的四个步骤
内存泄漏的典型表现:老年代使用率持续上升,Full GC越来越频繁,最终OOM,下面这套排查路径可以帮你快速定位。
第一步:确认是否真的泄漏
- 通过jstat -gcutil观察老年代占用率,如果一次Full GC后占用率几乎没有下降,或者下降后很快回升,基本可以判断存在泄漏。
- 或者用jcmd
第二步:获取堆转储并分析
- 在泄漏发生前或发生时,用jmap或jcmd生成堆转储(heap.hprof)。
- 推荐用MAT(Memory Analyzer Tool)或Eclipse Memory Analyzer打开,重点关注:
- 可疑的GC Root引用链。
- 占用内存最大的对象(通常是byte[]或java.util.HashMap$Node)。
- 重复的字符串或集合类。
第三步:定位泄漏源
- 在MAT中查看Leak Suspects报告,工具会给出大概率泄漏的路径。
- 比如ThreadLocal未清理、静态集合持有对象、缓存无过期策略、第三方库(如Netty、Kafka)的缓冲区泄漏。
第四步:结合业务代码复现
- 如果在线环境不方便长期分析,搭建压测环境复现相同场景,通过JProfiler或YourKit进行实时监控。
- 重点观察对象的老化路径和引用全路径,修复后对比堆内存变化即可验证。
JVM监控方案对比:免费工具与商业工具怎么选?
市面上JVM监控工具种类繁多,选型时需要考虑团队技术栈、预算和运维复杂度,下面这个表格帮你快速对比主流方案。
| 工具 | 类型 | 核心功能 | 适用场景 |
|---|---|---|---|
| jstat/jmap/jcmd | 命令行 | 实时查看堆内存、GC、转储 | 临时排查,无运维开销 |
| VisualVM | 免费GUI | 堆内存、线程、GC可视化 | 本地开发和小规模测试 |
| Java Mission Control(JMC) | 免费(需JDK商业授权) | 飞行记录、实时分析 | 对JVM底层有深入需求的团队 |
| Arthas | 开源CLI | 在线诊断、火焰图、实时监控 | 生产环境一键排查,无侵入 |
| Prometheus + Grafana | 开源组合 | 历史趋势、告警、Dashboard | 规模化集群监控,可定制 |
| Azure Monitor/CloudWatch | 商业云服务 | 全托管,与云资源联动 | 使用云原生服务的团队 |
如果你的团队只有几台服务器,命令行+Arthas基本够用,如果管理上百个节点,业内专家指出,Prometheus + Grafana + JMX Exporter是最稳定且性价比高的方案,行业共识认为,商业工具(如AppDynamics、Dynatrace)在自动发现和告警准确率上更优,但成本较高,适合对故障响应要求极高的场景。
JVM监控内存实战:使用Grafana搭建可视化监控
手把手教你搭一套JVM内存监控看板,覆盖堆内存、元空间、GC信息。
暴露JMX指标
- 启动Java应用时添加JMX Exporter参数(适用于Prometheus),或者使用jmx_prometheus_javaagent jar包。
- 示例:
-javaagent:./jmx_prometheus_javaagent-0.18.0.jar=9404:config.yaml,config.yaml里定义需要采集的指标(如堆内存、元空间、GC)。
配置Prometheus
- 在prometheus.yml中添加target:job_name: 'jvm-monitor', static_configs: [{'targets': ['localhost:9404']}]。
- 重启Prometheus,确认target状态为UP。
导入Grafana看板
- 在Grafana中搜索Dashboard ID:4701(JVM Dashboard),导入后即可看到堆内存趋势、GC时间、线程数等。
- 也可以自定义看板,重点关注以下几个Panel:
- 堆内存使用率(当前值/最大值)。
- 老年代和新生代使用量。
- GC次数和停顿时间(P99指标)。
- 元空间使用率。
设置告警
- 堆内存使用率超过80%持续5分钟触发告警。
- 老年代占用率持续上升且Full GC间隔缩短,需要人工介入。
- 元空间使用率超过85%检查类加载情况。
Q&A:JVM监控内存常见问题
JVM监控内存命令有哪些?
最常用的四个命令:jstat(查看GC和堆内存百分比)、jmap(堆转储和直方图)、jcmd(多功能诊断)、jstack(线程栈,配合CPU问题),线上排查时优先用jstat观察趋势,用jmap dump分析泄漏。
JVM监控内存总是突然飙升,怎么看是GC问题还是泄漏?
先看GC频率:如果GC后内存使用率明显下降,那是对象创建过多导致临时压力;如果GC后内存几乎不变,或者下降后立刻回升,那基本是泄漏,这时候用jmap dump出堆,用MAT分析保留对象最多的路径,就能找到泄漏源。



