对象在jvm堆内存中的生命周期为“创建→可达→不可达→回收”,gc通过可达性分析判定垃圾,分代回收:年轻代用复制算法,老年代用标记-整理或标记-清除,g1按region收益回收,zgc/shenandoah支持并发以降低stw。

JVM垃圾回收与堆内存性能分析,关键在于把“对象生命周期”和“回收行为”对应起来看。堆结构不是静态容器,而是一套动态协作机制;GC不是后台清洁工,而是受参数驱动的实时决策系统。调优不是调数字,而是校准这套机制与业务节奏的匹配度。
看清堆内存的真实分工
堆不是一块均匀内存,而是按对象存活时间划分的协作单元:
- Eden区占年轻代80%,新对象默认在此分配,TLAB(线程本地缓冲)进一步加速分配
- 两个Survivor区各占10%,用于Minor GC后存活对象的“暂存+年龄累加”,不是永久中转站
- 老年代不存“老年对象”,只存被判定为“大概率长期存活”的对象——比如缓存、连接池、Spring单例Bean
- 元空间(Metaspace)独立于堆,存放类元数据,默认无上限,但需用-XX:MaxMetaspaceSize防失控增长
识别GC问题的典型信号
不能只看“有没有GC”,要看GC在什么位置、以什么频率、付出什么代价:
- 频繁Minor GC(每秒多次)→ Eden太小或对象创建过快,可能伴随Survivor区溢出、提前晋升
- 老年代持续缓慢上涨 → 内存泄漏迹象,或缓存未设淘汰策略,需用jmap -histo查大对象分布
- Full GC间隔短且耗时长 → 老年代碎片化严重(CMS)或G1 Mixed GC触发过晚,也可能是元空间OOM前兆
- GC日志中出现“to-space overflow”或“promotion failed” → Survivor区或老年代空间不足,对象被迫直接进入老年代
选对回收器比调参更重要
回收器决定底层行为逻辑,参数只是微调。脱离场景谈参数等于纸上谈兵:
- 响应敏感型服务(如API网关、实时交易):优先G1(JDK8u262+)、ZGC(JDK11+)或Shenandoah(JDK12+),用-XX:MaxGCPauseMillis=200设目标停顿,而非硬限
- 批处理/后台任务:Parallel GC更合适,用-XX:GCTimeRatio=19(即GC时间占比≤5%)保吞吐
- 4GB以下小堆:Serial或Parallel足够,不必强上G1增加复杂度
- CMS已从JDK14起移除,生产环境必须替换,不可依赖
用对工具才能看见真实瓶颈
凭感觉调优风险极高,所有结论必须来自可观测数据:
- 启动时加-Xlog:gc*:file=gc.log:time,uptime,pid,tags(JDK10+),替代老旧的-XX:+PrintGCDetails
-
jstat -gc -h10
1000 观察Eden、Survivor、老年代使用率变化斜率,判断分配速率与回收效率是否失衡 - 内存飙升时,用jcmd
VM.native_memory summary 确认是堆内还是Direct Memory/NIO缓冲区泄漏 - 可视化分析推荐GCViewer(轻量)或Elastic APM(生产级),避免人工扫日志漏掉“停顿时间毛刺”











