官方介绍:
Getting Started with the G1 Garbage Collector
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/
概述:
- G1收集器适用于要求大内存(大堆)、低时延的应用服务。
- G1收集器大概率可以在满足GC停顿时间要求的情况下,实现服务的高吞吐量。
- G1收集器的目标是为了替代CMS收集器。
G1收集器与CMS收集器的区别:
- G1提供了比CMS收集器更可预测的垃圾收集暂停,并允许用户指定所需的暂停目标。
- 传统的分代收集器每个代的存储空间是连续的,G1每个代的存储空间不是连续的,只是在逻辑上是连续的。不必每次GC都去处理整个堆空间,而是每次只处理一部分 Region,实现大容量内存的 GC。
CMS收集器是否应该切换到G1收集器?
使用CMS 或 Parallel Old 收集器的应用如果出现以下场景,建议切换为G1收集器:
- Full GC 持续时间太长或太频繁。
- 对象分配速度 或 对象晋升速度 的变化幅度很大。
- 不希望有长时间(超过0.5到1秒)垃圾收集或压缩带来的STW。
基础概念:
Region
-
堆被分成大约2000个大小相等的region,region的大小在1M~32Mb之间,region一共有5种类型:
-
年轻代:
-
eden类型:所有eden类型的region在逻辑上组成了堆中年轻代的eden区。
-
survivor类型:所有survivor类型的region在逻辑上组成了堆中年轻代的survivor区。
-
说明:年轻代由一组不连续的region组成,故年轻代在需要调整大小时变的很轻松。
-
-
老年代:
-
old类型:
-
humongous类型:
-
用来存储巨大对象,巨大对象的大小大于标准region大小的50%。
-
一般情况下,jvm使用一组相邻的humongous类型region来存储巨大对象。
-
humongous类型region的作用是让大对象直接进入老年代,避免了大对象在新生代反复的迁移(复制清理)。
-
-
说明:所有 old类型 + humongous类型 的region组成了堆的老年代。
-
-
堆未使用的region:
停顿预测模型(Pause Prediction Model):
- G1会根据历史的收集数据计算出本次每个region的回收价值(回收所需时间、可回收空间等)并在后台维护一个优先列表,垃圾收集时优先回收价值最大的region,G1通过这种方式把垃圾回收带来的暂停时间尽量控制在目标暂停时间之内,这就是G1的暂停时间预测模型,同时G1(Garbage-First)名称也因此而来。
GC模式:
收集算法:
- 从整体上看,G1是采用“标记-整理”算法,从局部(两个region之间)上看采用“复制”算法。
GC类型:
- 只有Young GC 和 Mixed GC两只gc类型。
- 如果Mixed GC无法跟上程序分配内存的速度,则会导致老年代被耗尽,此时jvm就会使用serial old GC(full GC)来收集整个堆。
Young GC
- 触发时机:当新对象无法在eden区分配内存时会触发YGC。
- 收集范围:年轻代(Eden/Survivor)所有region中的垃圾对象。
- 收集过程:
- 采用复制算法,对存活的对象进行迁移(evacuation):
- 复制:将年轻代中存活的对象复制到一个或多个survivor region中,满足晋升条件的对象会直接进入老年代。
- 清理:对年轻代中无存活对象的region进行清理。
- 重新计算规划eden区和survivor区的大小,jvm在计算时会将目标暂停时间考虑进去。这样,jvm就可以通过动态改变年轻代region的个数来控制young gc的时间开销。
- 采用复制算法,对存活的对象进行迁移(evacuation):
- 收集方式:并行收集,收集过程会STW。
全局并发标记(global concurrent marking)
- 触发时机:整个堆被占用的比例超过某个阈值(-XX:InitiatingHeapOccupancyPercent,默认为45)时会触发G1的全局并发标记。
- 目的:统计出哪些old region可以被回收 以及 回收这些region可以带来的收益,在mixed gc时会根据这些统计信息选择收益较高的region进行回收。
- 标记过程:
- 初始标记(initial-mark):
- 初始标记开始时,通常会伴随一次Young GC:
- 这样做的好处是初始标记可以借助YGC的STW来完成,而不需要另外的STW。
- 需要注意的是:初始标记与YGC在逻辑上是相互独立的。
- YGC:过程中将年轻代中存活的对象都迁移到一个或多个surviror中。
- 初始标记:扫描这些存放年轻代存活对象的surviror region,然后标记出引用了老年代对象的surviror region,这些survivor region被认为是根区域(root region),该过程会STW。
- it is piggybacked on a normal young GC. Mark survivor regions (root regions) which may have references to objects in old generation.
- 初始标记开始时,通常会伴随一次Young GC:
- 根区域扫描(concurrent-root-region-scan)
- 通过扫描根区域中的对象(根对象:gc-root)来标记老年代中离根对象最近的对象,并把这些对象压入扫描栈(marking stack)中等到后续扫描。
- 该阶段与应用程序并发运行,不需要STW。
- 根区域扫描必须在下一次YGC启动前完成,因为每次YGC都会产生新的surivor region。如果在根区域扫描过程中eden区耗尽,那么新一轮的YGC只能等待本次根区域扫描完成后才能启动。
- 如果在gc日志中发现:根分区扫描的日志和YGC的日志交替出现,那么这个应用的GC就需要调优了。
- Scan survivor regions for references into the old generation. This happens while the application continues to run. The phase must be completed before a young GC can occur.
- 并发标记(concurrent-mark)
- 从扫描栈中获取根区域扫描阶段标记的老年代对象,然后通过这些对象的引用链,将整个堆中存活的对象都标记出来。
- 标记线程与应用程序线程并发执行,不需要STW,且该阶段可能会被YGC打断。
- Find live objects over the entire heap. This happens while the application is running. This phase can be interrupted by young generation garbage collections.
- 最终标记(remark)
- 使用初始快照算法(SATB),通过扫描记录 发生变化的引用关系 的队列来标记并发过程中又存活的对象,进而完成堆中存活对象的标记,该阶段会STW。
- Completes the marking of live object in the heap. Uses an algorithm called snapshot-at-the-beginning (SATB) which is much faster than what was used in the CMS collector.
- 垃圾清理(cleanup)
- 统计出哪些old region可以被回收 以及 回收这些region可以带来的收益,该过程会STW。(注意:cleanup阶段并没有对存活的对象进行迁移,对象迁移的工作会在之后的YGC或Mixed GC中进行。)
- 重新维护每个region各自的RSet,该过程会STW。
- 统计出完全空闲的region,然后重置这些空闲的region并将它们添加到可分配到region列表中,该过程与应用线程并发。
- Performs accounting on live objects and completely free regions. (Stop the world)
- Scrubs the Remembered Sets. (Stop the world)
- Reset the empty regions and return them to the free list. (Concurrent)
- 初始标记(initial-mark):
Mixed GC
- 触发时机:在全局标记结束之后,若可被回收的垃圾占整个堆的比例超过指定阈值(默认5%),则会触发Mixed GC。
- 收集范围:选定Young区中全部的Region,根据全局并发标记阶段统计得出收集收益高的若干老年代 Region(在用户指定的开销目标范围内尽可能选择收益高的老年代Region)。
- 收集过程:
- 采用复制算法,对存活的对象进行evacuation(复制+清理)
- 若只回收年轻代中的对象,则evacuation由YGC完成。
- 若回收年轻代中+部分老年代对象,则evacuation由Mixed GC完成。
- These are the stop the world pauses to evacuate or copy live objects to new unused regions.
- This can be done with young generation regions which are logged as [GC pause (young)]. Or both young and old generation regions which are logged as [GC Pause (mixed)].
- 采用复制算法,对存活的对象进行evacuation(复制+清理)
- 收集方式:收集的整个过程会STW。
收集集合(Collection Set / CSet)
- 记录了要被回收的region,这些region可以是任意类型(eden、survivor、old)的region。
- 在GC过程中,CSet中存活的对象会被移动到另一个可用region中。
参数:
参数列表:
Option and Default Value | Description |
---|---|
-XX:+UseG1GC | Use the Garbage First (G1) Collector |
默认参数
Option and Default Value | Description |
---|---|
-XX:G1HeapRegionSize=n |
|
-XX:MaxGCPauseMillis=200 |
|
-XX:G1NewSizePercent=5 | Sets the percentage of the heap to use as the minimum for the young generation size. The default value is 5 percent of your Java heap.Foot1 This is an experimental flag. See How to Unlock Experimental VM Flags for an example. This setting replaces the -XX:DefaultMinNewGenPercent setting. |
| Sets the percentage of the heap size to use as the maximum for young generation size. The default value is 60 percent of your Java heap.Footref1 This is an experimental flag. See How to Unlock Experimental VM Flags for an example. This setting replaces the |
|
|
|
|
|
|
|
Sets the occupancy threshold for an old region to be included in a mixed garbage collection cycle. The default occupancy is 85 percent .Footref1 This is an experimental flag. See How to Unlock Experimental VM Flags for an example. This setting replaces the |
| Sets the percentage of heap that you are willing to waste. The Java HotSpot VM does not initiate the mixed garbage collection cycle when the reclaimable percentage is less than the heap waste percentage. The default is 5 percent.Footref1 指定触发Mixed GC的堆垃圾占比,默认值5%。
|
| 设置在一次全局并发标记之后执行Mixed GC的最大次数,默认最多8次。 Sets the target number of mixed garbage collections after a marking cycle to collect old regions with at most |
| Sets an upper limit on the number of old regions to be collected during a mixed garbage collection cycle. The default is 10 percent of the Java heap.Footref1 |
|
|
Footnote1 This setting is not available in Java HotSpot VM build 23 or earlier.
最佳实践:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html#recommendations
一、年轻代大小:
不要通过-Xmn参数来显式设置年轻代的大小:
- 显示设置年轻代的大小会导致G1不能按需调整年轻代的大小,进而在gc时将不再考虑目标暂停时间。
二、目标暂停时间:
- G1的吞吐量目标是:90%的时间用于应用程序,10%的时间用于垃圾手机。通过MaxGCPauseMillis设置暂停的目标时间时,G1将尝试满足这个目标,但是吞吐量可能会受到影响。
三、mix gc 调整
-
-XX:InitiatingHeapOccupancyPercent
: Use to change the marking threshold. -
-XX:G1MixedGCLiveThresholdPercent
and-XX:G1HeapWastePercent
: Use to change the mixed garbage collection . -
-XX:G1MixedGCCountTarget
and-XX:G1OldCSetRegionThresholdPercent
: Use to adjust the CSet for old regions.
尽量避免存活对象迁移失败(Evacuation Failure)的情况:
- 增加堆预留空间的大小:-XX:G1ReservePercent默认为10,调大该值。
- 增加标记线程的数量:-XX:ConcGCThreads=n,默认是-XX:ParallelGCThreads的1/4。