这块其实是在讲JVM 调优不是为了“调参数而调参数”而是因为不同内存区域大小、GC 收集器策略会直接影响 GC 次数、GC 耗时、对象晋升、Full GC 概率最终影响接口响应时间和系统稳定性。我按你的内容拆开解释。一、JVM 为什么需要调优JVM 默认参数一般是能跑的而且大多数普通业务不一定需要手动调优。但是如果你的业务有这些特点就可能需要调优接口响应时间要求高比如 C 端接口要求 100ms 内返回。并发量高内存分配快大量请求不断创建对象Eden 区很快被填满。GC 频繁Young GC、Old GC、Full GC 次数太多会影响吞吐和响应时间。GC 停顿时间太长GC 期间会 STW业务线程暂停请求就会卡住。所以 JVM 调优的核心目标通常是减少 GC 次数降低 GC 停顿时间避免高峰期 Full GC提升系统稳定性。二、可以调什么图里主要分成三块1. 堆内存堆里面主要有年轻代Eden Survivor0 Survivor1 老年代Old Generation可以调-Xms 堆初始大小 -Xmx 堆最大大小 -Xmn 年轻代大小 -XX:NewSize -XX:MaxNewSize -XX:SurvivorRatio -XX:MaxTenuringThreshold其中-XmsJVM 启动时堆的初始大小 -XmxJVM 最大可用堆大小 -Xmn年轻代大小一般线上会把-Xms和-Xmx设置成一样避免 JVM 运行过程中动态扩容或缩容带来额外开销。2. 方法区 / 元空间JDK8 以后永久代被移除改成了元空间 Metaspace。元空间不在堆里而是在本地内存中主要存放类元信息 方法元信息 常量池相关信息 类加载器信息可以调-XX:MetaspaceSize -XX:MaxMetaspaceSize注意元空间不在堆中但元空间不足也可能触发 Full GC。如果 Full GC 后还是释放不了足够的类元数据就可能报OutOfMemoryError: Metaspace3. 垃圾收集器比如ParNew CMS G1 Parallel Scavenge Parallel Old ZGC Shenandoah不同垃圾收集器的目标不同CMS低延迟减少老年代 STW 时间 G1可预测停顿时间适合较大堆 Parallel吞吐量优先 ZGC超低延迟三、Eden 区大小为什么会影响 GC年轻代大致是这样Eden 区新对象主要分配在这里 Survivor 区Young GC 后存活对象进入这里Eden 太小会怎样Eden 小放不下太多新对象。比如每秒创建很多对象Eden 很快满了就会频繁触发 Young GC。Eden 小 ↓ 对象很快填满 Eden ↓ Young GC 频繁 ↓ 业务线程频繁 STW ↓ 接口响应变慢所以 Eden 太小的问题是Young GC 次数太多。Eden 太大会怎样Eden 大Young GC 没那么频繁。但一旦触发 Young GC需要扫描和处理的对象范围更大单次 Young GC 可能耗时更长。Eden 大 ↓ Young GC 次数减少 ↓ 但单次 Young GC 可能更久所以 Eden 不是越大越好而是要在GC 频率 GC 单次耗时之间找平衡。四、为什么 Young GC 会影响接口响应因为 Young GC 是 STW 的。STW 的意思是Stop The WorldGC 期间用户线程暂停。举个例子接口本来 10ms 能处理完 执行到第 5ms 时发生 Young GC Young GC 停顿 50ms 接口总耗时 5ms 50ms 5ms 60ms如果业务要求接口 50ms 内返回那这次请求就超时了。所以调优不是只看平均耗时还要看GC 最大停顿时间 P95 / P99 接口耗时 高峰期 GC 情况五、Survivor 区大小有什么影响年轻代结构一般是Eden : From Survivor : To Survivor 8 : 1 : 1每次 Young GC 后Eden 中存活对象 From Survivor 中存活对象 ↓ 复制到 To Survivor然后 From 和 To 交换角色。Survivor 太小会怎样如果 Survivor 太小Young GC 后存活对象放不下就会提前晋升到老年代。Survivor 太小 ↓ 存活对象放不下 ↓ 对象提前进入老年代 ↓ 老年代增长变快 ↓ Old GC / Full GC 更容易发生这个叫过早晋升。本来一些对象再经历几次 Young GC 就死了但因为 Survivor 放不下被迫进入老年代。这样会增加老年代压力。Survivor 太大会怎样Survivor 区有两个From Survivor To Survivor但每次只有一个 Survivor 区真正用来存放对象另一个是空着等待复制的。所以 Survivor 设置太大会浪费空间。Survivor 太大 ↓ 两个 Survivor 占用年轻代空间过多 ↓ Eden 变小 ↓ Young GC 可能更频繁所以 Survivor 也不是越大越好。六、CMS 中 Old GC 和 Full GC 的区别你这块说得很关键。在 CMS 里面Old GC主要针对老年代CMS 的老年代回收过程大致是初始标记 STW 并发标记 重新标记 STW 并发清理CMS 的目标是减少 STW 时间。Full GCFull GC 范围更大通常涉及年轻代 老年代 元空间/永久代相关回收在 CMS 中如果 CMS 回收失败可能触发 Full GC。比如老年代碎片太多 老年代空间不足 CMS 来不及回收 晋升失败 元空间不足都可能导致 Full GC。Full GC 往往比普通 Young GC、Old GC 更严重因为它停顿时间更长。七、案例一CMS 老年代碎片导致 Full GC环境JDK8 ParNew CMSParNew 负责年轻代CMS 负责老年代。问题现象高峰期发生 Full GCFull GC 耗时可能达到 1 秒。对 C 端接口来说1 秒非常严重。用户请求进来 ↓ 突然 Full GC ↓ 业务线程全部暂停 1 秒 ↓ 大量请求超时原因分析CMS 使用的是标记清除算法标记清除的特点是优点速度快不移动对象 缺点产生内存碎片比如老年代内存看起来还有很多剩余空间总剩余空间500MB但这些空间是零散的10MB 20MB 5MB 30MB ...如果此时要分配一个 100MB 的大对象就可能失败。因为 JVM 需要的是连续空间不是总空间够就行。于是出现老年代还有空间 但没有足够连续空间 ↓ 分配失败 ↓ 触发 Full GC优化策略在业务低峰期比如凌晨 4 点显式触发一次 Full GCSystem.gc();在 CMS 下Full GC 可能退化为 Serial Old。Serial Old 使用标记整理算法标记整理会移动对象把存活对象整理到一边清理出连续空间。碎片化老年代 ↓ 低峰期 Full GC 标记整理 ↓ 老年代空间变连续 ↓ 高峰期 Full GC 概率降低这个方案的思路不是消灭 Full GC而是把不可避免的 Full GC 尽量安排到低峰期而不是让它在高峰期随机发生。面试表达可以这样说我了解过一个 CMS 调优案例。业务使用 ParNew CMS核心接口对响应时间要求很高。高峰期偶尔发生 Full GC停顿达到秒级。分析 GC 日志后发现CMS 使用标记清除算法长期运行后老年代碎片较多导致对象分配失败最终触发 Full GC。优化方案是在业务低峰期主动触发一次 Full GC让 CMS 退化为 Serial Old通过标记整理压缩老年代空间减少高峰期因为内存碎片导致的 Full GC。优化后高峰期 Full GC 明显减少。八、案例二年轻代太小导致 YGC 和 Old GC 都频繁问题现象Young GC 每分钟 50 次每次 25ms Old GC 几分钟 1 次每次 200ms说明两个问题YGC 太频繁 老年代增长也很快原因分析一开始年轻代设置较小目的是让 Young GC 单次耗时短。这个思路没错。但是随着业务量增长对象分配速度变快年轻代太小就撑不住了。年轻代太小 ↓ Eden 很快满 ↓ Young GC 频繁 ↓ Survivor 放不下部分存活对象 ↓ 对象提前晋升老年代 ↓ 老年代增长快 ↓ Old GC 也频繁所以这里的问题本质是年轻代容量已经不匹配当前业务对象分配速率。优化策略扩大年轻代到原来的 3 倍。效果单次 YGC 耗时增加 5% YGC 频率降低 60% Old GC 降低到几小时 1 次这里很重要的一点是年轻代扩大 3 倍不代表 Young GC 耗时也扩大 3 倍。因为 Young GC 使用的是复制算法主要成本不是 Eden 总大小而是存活对象数量大部分临时对象在 Young GC 时已经死了不需要复制。所以年轻代变大后Young GC 频率大幅下降 单次 Young GC 耗时只是轻微增加这是一个很典型的调优收益。九、案例三G1 的 MaxGCPauseMillis 设置太小环境JDK8 G1G1 和 CMS 不太一样。G1 会把堆划分成很多 RegionRegion 1 Region 2 Region 3 ...这些 Region 可以动态扮演Eden Survivor Old HumongousMaxGCPauseMillis 是什么-XX:MaxGCPauseMillis它表示期望的最大 GC 暂停时间目标。比如设置-XX:MaxGCPauseMillis50意思是告诉 G1我希望你尽量把 GC 停顿控制在 50ms 左右。注意它不是绝对保证而是一个目标。为什么设置太小会导致 Young GC 频繁如果你把暂停时间目标设置得特别小比如 20ms、30msG1 为了尽量满足这个目标就会减少每次 Young GC 要处理的 Region 数量。也就是暂停时间目标太小 ↓ G1 不敢让年轻代太大 ↓ 年轻代 Region 数量减少 ↓ Eden 更容易满 ↓ Young GC 更频繁所以问题不是 G1 本身不好而是停顿时间目标设置得过于激进导致 G1 自动把年轻代调得太小。优化方案有两种方案一调大 MaxGCPauseMillis比如从50ms调到100ms 或 200ms让 G1 有更大的调节空间。暂停目标放宽 ↓ G1 可以使用更大的年轻代 ↓ Young GC 频率下降方案二固定年轻代大小可以设置年轻代占比例如-XX:G1NewSizePercent -XX:G1MaxNewSizePercent让年轻代不要被 G1 自动调得太小。不过一般来说G1 更推荐让 JVM 自己动态调整除非你很明确知道问题在年轻代过小。十、怎么判断到底该不该调 JVM面试回答里最好不要说我上来就改 JVM 参数。更合理的流程是1. 先配置监控告警 2. 发现 GC 指标异常 3. 查看 GC 日志 4. 分析是 Young GC、Old GC、Full GC 哪类问题 5. 结合业务对象分配情况判断原因 6. 小步调整参数 7. 压测验证 8. 灰度上线重点监控指标包括Young GC 次数 Young GC 平均耗时 / 最大耗时 Old GC 次数 Full GC 次数 Full GC 耗时 堆使用率 老年代使用率 元空间使用率 对象晋升速率 接口 P95 / P99 响应时间十一、这部分可以整理成面试回答你可以这样说JVM 调优本质上是根据业务运行情况调整内存区域大小和垃圾收集器策略目标是减少 GC 次数、降低 STW 时间、避免高峰期 Full GC。一般默认 JVM 参数在大多数场景下是够用的不建议一开始就盲目调参。更合理的方式是先建立 GC 监控和告警比如 Young GC 次数、Young GC 耗时、Old GC 次数、Full GC 次数、老年代使用率、元空间使用率等。出现异常后再结合 GC 日志分析。比如年轻代太小会导致 Eden 很快被填满从而 Young GC 频繁Survivor 太小会导致对象过早晋升到老年代增加 Old GC 或 Full GC 概率CMS 使用标记清除算法长期运行会产生内存碎片可能导致老年代还有剩余空间但没有连续空间分配对象最终触发 Full GC。我了解过一个 ParNew CMS 的案例业务高峰期偶尔发生秒级 Full GC影响接口响应。分析后发现是 CMS 老年代碎片较多导致对象分配失败。优化方案是在业务低峰期主动触发 Full GC让 Serial Old 做一次标记整理压缩老年代空间减少高峰期 Full GC 概率。另一个案例是年轻代设置过小导致 Young GC 每分钟几十次并且对象过早晋升老年代引发 Old GC 频繁。后来扩大年轻代后单次 Young GC 耗时只略微上升但 Young GC 频率和 Old GC 频率明显下降。如果是 G1常见问题是 MaxGCPauseMillis 设置太小G1 为了满足停顿目标会自动缩小年轻代 Region 数量反而导致 Young GC 频繁。这时可以适当放宽 MaxGCPauseMillis或者在明确问题时固定年轻代大小。十二、最后总结一句JVM 调优可以抓住这条主线内存区域大小 ↓ 影响对象分配和晋升 ↓ 影响 GC 频率和 GC 耗时 ↓ 影响接口响应时间和系统稳定性所以调优不是背参数而是要回答清楚为什么 GC 频繁 为什么 Full GC 为什么对象提前进老年代 为什么停顿时间变长 调整哪个区域能缓解这个问题这才是面试官真正想听的。
【JVM】JVM调优经验
这块其实是在讲JVM 调优不是为了“调参数而调参数”而是因为不同内存区域大小、GC 收集器策略会直接影响 GC 次数、GC 耗时、对象晋升、Full GC 概率最终影响接口响应时间和系统稳定性。我按你的内容拆开解释。一、JVM 为什么需要调优JVM 默认参数一般是能跑的而且大多数普通业务不一定需要手动调优。但是如果你的业务有这些特点就可能需要调优接口响应时间要求高比如 C 端接口要求 100ms 内返回。并发量高内存分配快大量请求不断创建对象Eden 区很快被填满。GC 频繁Young GC、Old GC、Full GC 次数太多会影响吞吐和响应时间。GC 停顿时间太长GC 期间会 STW业务线程暂停请求就会卡住。所以 JVM 调优的核心目标通常是减少 GC 次数降低 GC 停顿时间避免高峰期 Full GC提升系统稳定性。二、可以调什么图里主要分成三块1. 堆内存堆里面主要有年轻代Eden Survivor0 Survivor1 老年代Old Generation可以调-Xms 堆初始大小 -Xmx 堆最大大小 -Xmn 年轻代大小 -XX:NewSize -XX:MaxNewSize -XX:SurvivorRatio -XX:MaxTenuringThreshold其中-XmsJVM 启动时堆的初始大小 -XmxJVM 最大可用堆大小 -Xmn年轻代大小一般线上会把-Xms和-Xmx设置成一样避免 JVM 运行过程中动态扩容或缩容带来额外开销。2. 方法区 / 元空间JDK8 以后永久代被移除改成了元空间 Metaspace。元空间不在堆里而是在本地内存中主要存放类元信息 方法元信息 常量池相关信息 类加载器信息可以调-XX:MetaspaceSize -XX:MaxMetaspaceSize注意元空间不在堆中但元空间不足也可能触发 Full GC。如果 Full GC 后还是释放不了足够的类元数据就可能报OutOfMemoryError: Metaspace3. 垃圾收集器比如ParNew CMS G1 Parallel Scavenge Parallel Old ZGC Shenandoah不同垃圾收集器的目标不同CMS低延迟减少老年代 STW 时间 G1可预测停顿时间适合较大堆 Parallel吞吐量优先 ZGC超低延迟三、Eden 区大小为什么会影响 GC年轻代大致是这样Eden 区新对象主要分配在这里 Survivor 区Young GC 后存活对象进入这里Eden 太小会怎样Eden 小放不下太多新对象。比如每秒创建很多对象Eden 很快满了就会频繁触发 Young GC。Eden 小 ↓ 对象很快填满 Eden ↓ Young GC 频繁 ↓ 业务线程频繁 STW ↓ 接口响应变慢所以 Eden 太小的问题是Young GC 次数太多。Eden 太大会怎样Eden 大Young GC 没那么频繁。但一旦触发 Young GC需要扫描和处理的对象范围更大单次 Young GC 可能耗时更长。Eden 大 ↓ Young GC 次数减少 ↓ 但单次 Young GC 可能更久所以 Eden 不是越大越好而是要在GC 频率 GC 单次耗时之间找平衡。四、为什么 Young GC 会影响接口响应因为 Young GC 是 STW 的。STW 的意思是Stop The WorldGC 期间用户线程暂停。举个例子接口本来 10ms 能处理完 执行到第 5ms 时发生 Young GC Young GC 停顿 50ms 接口总耗时 5ms 50ms 5ms 60ms如果业务要求接口 50ms 内返回那这次请求就超时了。所以调优不是只看平均耗时还要看GC 最大停顿时间 P95 / P99 接口耗时 高峰期 GC 情况五、Survivor 区大小有什么影响年轻代结构一般是Eden : From Survivor : To Survivor 8 : 1 : 1每次 Young GC 后Eden 中存活对象 From Survivor 中存活对象 ↓ 复制到 To Survivor然后 From 和 To 交换角色。Survivor 太小会怎样如果 Survivor 太小Young GC 后存活对象放不下就会提前晋升到老年代。Survivor 太小 ↓ 存活对象放不下 ↓ 对象提前进入老年代 ↓ 老年代增长变快 ↓ Old GC / Full GC 更容易发生这个叫过早晋升。本来一些对象再经历几次 Young GC 就死了但因为 Survivor 放不下被迫进入老年代。这样会增加老年代压力。Survivor 太大会怎样Survivor 区有两个From Survivor To Survivor但每次只有一个 Survivor 区真正用来存放对象另一个是空着等待复制的。所以 Survivor 设置太大会浪费空间。Survivor 太大 ↓ 两个 Survivor 占用年轻代空间过多 ↓ Eden 变小 ↓ Young GC 可能更频繁所以 Survivor 也不是越大越好。六、CMS 中 Old GC 和 Full GC 的区别你这块说得很关键。在 CMS 里面Old GC主要针对老年代CMS 的老年代回收过程大致是初始标记 STW 并发标记 重新标记 STW 并发清理CMS 的目标是减少 STW 时间。Full GCFull GC 范围更大通常涉及年轻代 老年代 元空间/永久代相关回收在 CMS 中如果 CMS 回收失败可能触发 Full GC。比如老年代碎片太多 老年代空间不足 CMS 来不及回收 晋升失败 元空间不足都可能导致 Full GC。Full GC 往往比普通 Young GC、Old GC 更严重因为它停顿时间更长。七、案例一CMS 老年代碎片导致 Full GC环境JDK8 ParNew CMSParNew 负责年轻代CMS 负责老年代。问题现象高峰期发生 Full GCFull GC 耗时可能达到 1 秒。对 C 端接口来说1 秒非常严重。用户请求进来 ↓ 突然 Full GC ↓ 业务线程全部暂停 1 秒 ↓ 大量请求超时原因分析CMS 使用的是标记清除算法标记清除的特点是优点速度快不移动对象 缺点产生内存碎片比如老年代内存看起来还有很多剩余空间总剩余空间500MB但这些空间是零散的10MB 20MB 5MB 30MB ...如果此时要分配一个 100MB 的大对象就可能失败。因为 JVM 需要的是连续空间不是总空间够就行。于是出现老年代还有空间 但没有足够连续空间 ↓ 分配失败 ↓ 触发 Full GC优化策略在业务低峰期比如凌晨 4 点显式触发一次 Full GCSystem.gc();在 CMS 下Full GC 可能退化为 Serial Old。Serial Old 使用标记整理算法标记整理会移动对象把存活对象整理到一边清理出连续空间。碎片化老年代 ↓ 低峰期 Full GC 标记整理 ↓ 老年代空间变连续 ↓ 高峰期 Full GC 概率降低这个方案的思路不是消灭 Full GC而是把不可避免的 Full GC 尽量安排到低峰期而不是让它在高峰期随机发生。面试表达可以这样说我了解过一个 CMS 调优案例。业务使用 ParNew CMS核心接口对响应时间要求很高。高峰期偶尔发生 Full GC停顿达到秒级。分析 GC 日志后发现CMS 使用标记清除算法长期运行后老年代碎片较多导致对象分配失败最终触发 Full GC。优化方案是在业务低峰期主动触发一次 Full GC让 CMS 退化为 Serial Old通过标记整理压缩老年代空间减少高峰期因为内存碎片导致的 Full GC。优化后高峰期 Full GC 明显减少。八、案例二年轻代太小导致 YGC 和 Old GC 都频繁问题现象Young GC 每分钟 50 次每次 25ms Old GC 几分钟 1 次每次 200ms说明两个问题YGC 太频繁 老年代增长也很快原因分析一开始年轻代设置较小目的是让 Young GC 单次耗时短。这个思路没错。但是随着业务量增长对象分配速度变快年轻代太小就撑不住了。年轻代太小 ↓ Eden 很快满 ↓ Young GC 频繁 ↓ Survivor 放不下部分存活对象 ↓ 对象提前晋升老年代 ↓ 老年代增长快 ↓ Old GC 也频繁所以这里的问题本质是年轻代容量已经不匹配当前业务对象分配速率。优化策略扩大年轻代到原来的 3 倍。效果单次 YGC 耗时增加 5% YGC 频率降低 60% Old GC 降低到几小时 1 次这里很重要的一点是年轻代扩大 3 倍不代表 Young GC 耗时也扩大 3 倍。因为 Young GC 使用的是复制算法主要成本不是 Eden 总大小而是存活对象数量大部分临时对象在 Young GC 时已经死了不需要复制。所以年轻代变大后Young GC 频率大幅下降 单次 Young GC 耗时只是轻微增加这是一个很典型的调优收益。九、案例三G1 的 MaxGCPauseMillis 设置太小环境JDK8 G1G1 和 CMS 不太一样。G1 会把堆划分成很多 RegionRegion 1 Region 2 Region 3 ...这些 Region 可以动态扮演Eden Survivor Old HumongousMaxGCPauseMillis 是什么-XX:MaxGCPauseMillis它表示期望的最大 GC 暂停时间目标。比如设置-XX:MaxGCPauseMillis50意思是告诉 G1我希望你尽量把 GC 停顿控制在 50ms 左右。注意它不是绝对保证而是一个目标。为什么设置太小会导致 Young GC 频繁如果你把暂停时间目标设置得特别小比如 20ms、30msG1 为了尽量满足这个目标就会减少每次 Young GC 要处理的 Region 数量。也就是暂停时间目标太小 ↓ G1 不敢让年轻代太大 ↓ 年轻代 Region 数量减少 ↓ Eden 更容易满 ↓ Young GC 更频繁所以问题不是 G1 本身不好而是停顿时间目标设置得过于激进导致 G1 自动把年轻代调得太小。优化方案有两种方案一调大 MaxGCPauseMillis比如从50ms调到100ms 或 200ms让 G1 有更大的调节空间。暂停目标放宽 ↓ G1 可以使用更大的年轻代 ↓ Young GC 频率下降方案二固定年轻代大小可以设置年轻代占比例如-XX:G1NewSizePercent -XX:G1MaxNewSizePercent让年轻代不要被 G1 自动调得太小。不过一般来说G1 更推荐让 JVM 自己动态调整除非你很明确知道问题在年轻代过小。十、怎么判断到底该不该调 JVM面试回答里最好不要说我上来就改 JVM 参数。更合理的流程是1. 先配置监控告警 2. 发现 GC 指标异常 3. 查看 GC 日志 4. 分析是 Young GC、Old GC、Full GC 哪类问题 5. 结合业务对象分配情况判断原因 6. 小步调整参数 7. 压测验证 8. 灰度上线重点监控指标包括Young GC 次数 Young GC 平均耗时 / 最大耗时 Old GC 次数 Full GC 次数 Full GC 耗时 堆使用率 老年代使用率 元空间使用率 对象晋升速率 接口 P95 / P99 响应时间十一、这部分可以整理成面试回答你可以这样说JVM 调优本质上是根据业务运行情况调整内存区域大小和垃圾收集器策略目标是减少 GC 次数、降低 STW 时间、避免高峰期 Full GC。一般默认 JVM 参数在大多数场景下是够用的不建议一开始就盲目调参。更合理的方式是先建立 GC 监控和告警比如 Young GC 次数、Young GC 耗时、Old GC 次数、Full GC 次数、老年代使用率、元空间使用率等。出现异常后再结合 GC 日志分析。比如年轻代太小会导致 Eden 很快被填满从而 Young GC 频繁Survivor 太小会导致对象过早晋升到老年代增加 Old GC 或 Full GC 概率CMS 使用标记清除算法长期运行会产生内存碎片可能导致老年代还有剩余空间但没有连续空间分配对象最终触发 Full GC。我了解过一个 ParNew CMS 的案例业务高峰期偶尔发生秒级 Full GC影响接口响应。分析后发现是 CMS 老年代碎片较多导致对象分配失败。优化方案是在业务低峰期主动触发 Full GC让 Serial Old 做一次标记整理压缩老年代空间减少高峰期 Full GC 概率。另一个案例是年轻代设置过小导致 Young GC 每分钟几十次并且对象过早晋升老年代引发 Old GC 频繁。后来扩大年轻代后单次 Young GC 耗时只略微上升但 Young GC 频率和 Old GC 频率明显下降。如果是 G1常见问题是 MaxGCPauseMillis 设置太小G1 为了满足停顿目标会自动缩小年轻代 Region 数量反而导致 Young GC 频繁。这时可以适当放宽 MaxGCPauseMillis或者在明确问题时固定年轻代大小。十二、最后总结一句JVM 调优可以抓住这条主线内存区域大小 ↓ 影响对象分配和晋升 ↓ 影响 GC 频率和 GC 耗时 ↓ 影响接口响应时间和系统稳定性所以调优不是背参数而是要回答清楚为什么 GC 频繁 为什么 Full GC 为什么对象提前进老年代 为什么停顿时间变长 调整哪个区域能缓解这个问题这才是面试官真正想听的。