Java的G1(Garbage-First)垃圾回收流程是一个复杂但高效的过程,旨在提供可预测的停顿时间同时实现高吞吐量。以下是G1垃圾回收流程的主要步骤:
一、G1垃圾回收器概述
G1是Java HotSpot虚拟机中的一种垃圾收集器,自JDK7引入,并在JDK9中成为默认的垃圾回收器。G1将堆内存划分为多个大小相等的独立区域(Region),这些区域可以是Eden区、Survivor区或老年代(Old Generation)的一部分,也可以是专门用于存放大对象的Humongous区。
二、G1垃圾回收流程
1. 对象分配与年轻代回收(Young GC)
- 对象分配:新创建的对象首先被放置在Eden区。
- 触发条件:当Eden区空间使用率超过一定阈值(如60%容量),G1会触发Young GC。
- 回收过程:
- 停止应用线程(STW):暂停所有应用程序线程。
- 创建回收集(Collection Set):包括Eden区和Survivor区的所有内存分段。
- 扫描根(GC Roots):从GC Roots(如静态变量、局部变量等)和记忆集(Remembered Set, RS)记录的外部引用开始扫描存活对象。
- 更新记忆集(RS):处理dirty card queue中的card,更新RS,确保RS能准确反映老年代对年轻代对象的引用。
- 复制对象:将Eden区和Survivor区中存活的对象复制到另一个Survivor区或老年代(如果对象年龄达到阈值)。
- 处理引用:处理Soft、Weak、Phantom、Final、JNI Weak等引用。
- 结束回收:Eden区被清空,GC停止工作,对象在内存中连续存储,减少碎片。
2. 老年代并发标记过程(Concurrent Marking)
- 触发条件:当堆内存使用率达到预设阈值(如45%)时,G1会开始老年代并发标记过程。
- 初始标记(Initial Marking):标记GC Roots直接可达的对象,这是一个STW过程,但暂停时间较短。
- 根区域扫描(Root Region Scanning):扫描Survivor区直接可达的老年代区域对象,并标记被引用的对象。
- 并发标记(Concurrent Marking):在整个堆中并发标记对象,与应用程序线程并发执行。此过程可能会被Young GC打断。
- 再次标记(Remark):由于并发标记过程中应用程序线程仍在运行,需要再次标记以修正标记结果,这也是一个STW过程。
3. 混合回收(Mixed GC)
- 混合回收过程:在并发标记完成后,G1会进行混合回收,回收部分老年代和全部年轻代的Region。
- 对象移动:将老年代中存活的对象移动到空闲Region,这些空闲Region随后成为老年代的一部分。
- 回收策略:G1会优先回收垃圾占比较高的Region,以减少回收时间。
4. Full GC
- 触发条件:在极端情况下,如堆内存太小或对象分配速度远大于回收速度,G1会触发Full GC。
- 回收过程:停止所有应用程序线程,采用单线程进行标记、清理和压缩整理,释放空闲Region供后续使用。
三、总结
G1垃圾回收流程通过精确控制停顿时间、高效的并发标记和混合回收策略,实现了对Java堆内存的有效管理。它不仅提高了垃圾回收的效率和吞吐量,还减少了应用程序的停顿时间,从而提升了系统的整体性能。