G1和传统分代收集器(如 Parallel、CMS)对比
1.内存空间差异
G1 回收器仍然有 Eden、Survivor 和 Old 代的概念,但是它们的实现方式和传统的分代收集器有本质区别
传统分代收集器(如 Parallel、CMS):
text
+----------------------+
| Young Gen |
| +------+----------+ |
| | Eden | Survivor | |
| +------+----------+ |
+----------------------+
| Old Gen |
+----------------------+
- 连续内存区域:年轻代和老年代是连续的物理内存块
- 固定比例:通过
-XX:NewRatio、-XX:SurvivorRatio固定比例
G1 收集器:
text
+-----------------------------------+
| Region 0 | Region 1 | Region 2 | ... | Region N |
+-----------------------------------+
| Eden | Survivor | Old | Humongous | ... |
+-----------------------------------+
- Region 分区:堆被划分为多个大小相等的 Region(通常 1MB-32MB)
- 动态角色:每个 Region 可以动态充当 Eden、Survivor、Old 或 Humongous 区域
- 逻辑分代:Eden、Survivor、Old 是逻辑概念,物理上分散在不同的 Region 中
G1 回收器确实有 Young GC 和 Full GC,但它们的实现方式与传统收集器有所不同
2. G1 的 GC 类型
Young GC(年轻代垃圾回收)
触发条件:当 Eden Region 被填满时触发
执行过程:
- STW(Stop-The-World) :应用线程暂停
- 拷贝存活对象:将 Eden Region 和 Survivor Region 中的存活对象拷贝到新的 Survivor Region
- 年龄计数:对象年龄增加,达到阈值(默认15)的对象晋升到 Old Region
- Region 角色转换:原来的 Eden Region 变为空闲 Region
GC 日志示例:
text
[GC pause (G1 Evacuation Pause) (young)
[Eden: 100.0M(100.0M)->0.0B(1024.0K)
Survivors: 1024.0K->2048.0K
Heap: 100.0M(128.0M)->2048.0K(128.0M)]
Mixed GC(混合垃圾回收)
触发条件:当堆占用率达到 -XX:InitiatingHeapOccupancyPercent 阈值(默认45%)时,在并发标记周期后触发
执行过程:
- STW:应用线程暂停
- 同时回收:回收年轻代 Region + 部分老年代 Region(选择垃圾最多的 Region 优先回收)
- Garbage-First:基于 Region 的回收价值(垃圾比例)来决定回收顺序
GC 日志示例:
text
[GC pause (G1 Evacuation Pause) (mixed)
[Eden: 1024.0K(1024.0K)->0.0B(1024.0K)
Survivors: 2048.0K->1024.0K
Heap: 120.0M(128.0M)->80.0M(128.0M)]
Full GC(全局垃圾回收)
触发条件(G1 的设计目标就是尽量避免 Full GC!):
- 并发模式失败:回收速度跟不上分配速度
- 晋升失败:Young GC 时老年代没有足够空间接收晋升对象
- 大对象分配失败:无法找到连续的 Humongous Region
- 系统显式调用:
System.gc()(除非使用-XX:+ExplicitGCInvokesConcurrent)
| 回收方式 | 区域 | 触发条件 |
|---|---|---|
| Young GC(年轻代) | Eden Region Survivor Region | Eden Region 被填满时触发 |
| Mixed GC(混合) | 回收年轻代 Region + 部分老年代 Region | 堆占用率达阈值 |
| Full GC(全局) | 老年代 Region 和 Humongous Region | 老年代没有足够空间 无法找到连续的 Humongous Region |