新生代(Young Generation) 内部的三个区域**:Eden 区 和两个 Survivor 区(S0 和 S1)**
默认情况下,JVM 采用 8:1:1 的比例。这意味着如果新生代总共有 100MB 内存,Eden 区占 80MB,两个 Survivor 区各占 10MB。
以下是关于如何调节这个比例以及调节目的的详细说明:
⚙️ 1. 如何调节这个比例?
调节这个比例主要使用 JVM 参数 -XX:SurvivorRatio。
- 参数含义:该参数定义了 Eden 区 与 其中一个 Survivor 区 的大小比例。
- 默认值:8(即 Eden:S0:S1 = 8:1:1)。
- 计算公式:
- Eden 区占比 = N/(N+2)
- 每个 Survivor 区占比 = 1/(N+2)
- (其中 N 为 SurvivorRatio 的值 )
调节示例:
| 你的需求 | 设置参数 | 实际内存分布 (假设新生代 100MB) | 说明 |
|---|---|---|---|
| 默认配置 | -XX:SurvivorRatio=8 |
Eden: 80MB S0: 10MB, S1: 10MB | 适合大多数通用应用。 |
| 增大 Survivor 区 | -XX:SurvivorRatio=4 |
Eden: 66MB S0: 16.7MB, S1: 16.7MB | 适合需要延长对象在新生代停留时间的场景。 |
| 增大 Eden 区 | -XX:SurvivorRatio=10 |
Eden: 83MB S0: 8.3MB, S1: 8.3MB | 适合绝大多数对象都是"朝生夕死"的场景。 |
- 调节的目的是什么?
调节这个比例的核心目的是在 "减少 GC 频率 " 和 "避免对象过早晋升" 之间找到平衡点。
📉 场景一:调大 Survivor 区(减小 SurvivorRatio,如设为 4 或 6)
- 目的:防止对象过早晋升到老年代(Premature Promotion)。
- 原理:如果 Survivor 区太小(比如默认的 10%),当 Eden 区发生 Minor GC 后,存活的对象如果稍微多一点(超过 10%),Survivor 区就装不下了。这些"原本还能在新生代再活几轮"的对象会被直接强制送入老年代。
- 后果:老年代空间被快速填满,导致触发更耗时的 Full GC。
- 适用情况:当你发现应用中有很多对象不是"朝生夕死",而是会存活一小段时间,或者 GC 日志显示大量对象直接晋升到老年代时,应调大 Survivor 区(减小参数值)。
⏱️ 场景二:调大 Eden 区(增大 SurvivorRatio,如设为 10 或更高)
- 目的:降低 Minor GC 的触发频率。
- 原理:Eden 区越大,能容纳的新对象就越多,填满 Eden 区所需的时间就越长,因此触发 GC 的次数就会减少。
- 风险:如果 Eden 区过大,留给 Survivor 区的空间就会被压缩。一旦 Eden 区发生 GC,存活对象可能无法放入狭小的 Survivor 区,导致对象直接晋升老年代。
- 适用情况:如果你的应用中 99% 的对象都是"朝生夕死"(即存活率极低),那么 Survivor 区不需要很大,此时可以增大 Eden 区来提升吞吐量。
📌 总结与建议
| 调节方向 | 参数变化 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|---|
| 默认值 | SurvivorRatio=8 |
平衡了 GC 频率和晋升风险。 | 对特殊场景可能不是最优。 | 大多数标准 Web 应用。 |
| 增大 Survivor | SurvivorRatio=4 |
减少对象进入老年代,降低 Full GC 风险。 | Eden 区变小,Minor GC 频率可能略微增加。 | 对象存活率较高,或发现频繁 Full GC。 |
| 增大 Eden | SurvivorRatio=10 |
减少 Minor GC 次数,提升吞吐量。 | Survivor 区过小,容易导致对象过早晋升。 | 对象绝大多数都是"朝生夕死"。 |
最佳实践:*不要盲目修改这个参数。建议先开启 GC 日志(如 -Xlog:gc),观察 Minor GC 后存活对象的大小 与 Survivor 区大小 的关系。如果 Survivor 区经常被填满导致对象晋升,再考虑调大 Survivor 区(减小 SurvivorRatio)**。