堆内存使用趋势图是jvm性能分析核心入口,需结合used heap三种形态(健康锯齿状、阶梯式上涨、平台期高位横盘)及gc事件标记线、各代分层曲线综合判断;容器rss上涨但堆稳定时,重点排查直接内存、元空间和线程栈等堆外内存。

堆内存使用趋势图是JVM性能分析中最直观、最核心的观测入口,它不只反映“用了多少内存”,更揭示GC行为是否健康、对象生命周期是否合理、是否存在潜在泄漏。
Used Heap曲线:看懂它的三种典型形态
打开GC日志或用GCViewer、VisualVM等工具加载后,第一眼就该盯住Used Heap(已用堆内存)随时间变化的折线:
- 健康锯齿状:每次Minor GC后快速回落,老年代缓慢爬升,整体呈规律波浪——说明年轻代回收高效,对象短寿,系统运转正常
- 阶梯式上涨:每次GC后基线持续抬高(如每次+3%~5%),长期不回落——大概率存在缓存未清理、静态集合不断累积、监听器未注销等内存泄漏苗头
- 平台期高位横盘:内存长期卡在80%以上,GC频繁但回收量极少,used几乎不降——可能是大对象堆积、元空间/直接内存膨胀、或堆外内存占用干扰了JVM感知
必须叠加观察的两个关键维度
单看Used Heap容易误判,需同步关注:
- GC事件标记线:Minor GC(年轻代回收)通常密集且耗时短;Full GC(或G1 Mixed GC)间隔长但落差大。若Minor GC越来越频繁、耗时增长,说明Eden区过小或对象存活率升高
- 各代内存分层曲线:区分Young Gen Used、Old Gen Used、Metaspace Used。例如:Old Gen持续缓慢上升 + Young Gen回收后迅速填满 → 可能是对象过早晋升或Survivor区太小;Metaspace曲线陡升 → 类加载暴增(热部署、反射生成类过多)
容器内存增长但堆稳定?重点查这三处
当jstat -gc显示堆使用率正常(比如60%),但宿主容器(Docker/Pod)RSS持续上涨,问题往往不在堆内:
- 直接内存(Direct Memory):NIO ByteBuffer.allocateDirect()分配的堆外内存,不受-Xmx限制,需通过-XX:MaxDirectMemorySize控制
- 元空间(Metaspace):类定义、常量池、JIT代码缓存,用本地内存,溢出表现为java.lang.OutOfMemoryError: Metaspace
- 线程栈与本地代码:每个线程默认栈大小(-Xss)×线程数,JNI调用、压缩解压、图像处理等C库操作也会吃掉大量native memory
趋势图不是终点,而是定位起点
发现异常趋势后,下一步动作要明确:
- 阶梯/平台趋势 → 立即触发
jmap -dump:format=b,file=heap.hprof <pid></pid>抓堆快照,用MAT查dominator tree和leak suspect - Minor GC频繁 → 检查Eden占比(-XX:NewRatio)、Survivor容量(-XX:SurvivorRatio),尝试增大年轻代或调整晋升阈值(-XX:MaxTenuringThreshold)
- Old Gen缓慢爬升 → 结合jstat -gc输出中的YGC/FGC次数比、GCTime,判断是否因CMS/G1并发失败导致promotion failure











