JVM中的垃圾收集器 -- G1

官方介绍:

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的时间开销。
  • 收集方式:并行收集,收集过程会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.
    • 根区域扫描(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)

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)].
  • 收集方式:收集的整个过程会STW。

收集集合(Collection Set / CSet)

  • 记录了要被回收的region,这些region可以是任意类型(eden、survivor、old)的region。
  • 在GC过程中,CSet中存活的对象会被移动到另一个可用region中。

参数:

参数列表:

Option and Default ValueDescription
-XX:+UseG1GCUse the Garbage First (G1) Collector

默认参数

Option and Default ValueDescription
-XX:G1HeapRegionSize=n
  • Sets the size of a G1 region. The value will be a power of two and can range from 1 MB to 32 MB. The goal is to have around 2048 regions based on the minimum Java heap size.
  • With G1 the Java heap is subdivided into uniformly sized regions. This sets the size of the individual sub-divisions. The default value of this parameter is determined ergonomically based upon heap size. The minimum value is 1Mb and the maximum value is 32Mb.
-XX:MaxGCPauseMillis=200
  • Sets a target value for desired maximum pause time. The default value is 200 milliseconds. The specified value does not adapt to your heap size.
  • Sets a target for the maximum GC pause time. This is a soft goal, and the JVM will make its best effort to achieve it.
-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.

-XX:G1MaxNewSizePercent=60

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 -XX:DefaultMaxNewGenPercent setting.

-XX:ParallelGCThreads=n

  • Sets the value of the STW worker threads. Sets the value of n to the number of logical processors. The value of n is the same as the number of logical processors up to a value of 8.
  • If there are more than eight logical processors, sets the value of n to approximately 5/8 of the logical processors. This works in most cases except for larger SPARC systems where the value of n can be approximately 5/16 of the logical processors.
  • Sets the number of threads used during parallel phases of the garbage collectors. The default value varies with the platform on which the JVM is running.

-XX:ConcGCThreads=n

  • Sets the number of parallel marking threads. Sets n to approximately 1/4 of the number of parallel garbage collection threads (ParallelGCThreads).
  • Number of threads concurrent garbage collectors will use. The default value varies with the platform on which the JVM is running.

-XX:InitiatingHeapOccupancyPercent=45

  • Sets the Java heap occupancy threshold that triggers a marking cycle. The default occupancy is 45 percent of the entire Java heap.
  • Percentage of the (entire) heap occupancy to start a concurrent GC cycle. It is used by GCs that trigger a concurrent GC cycle based on the occupancy of the entire heap, not just one of the generations (e.g., G1). A value of 0 denotes 'do constant GC cycles'. The default value is 45.

-XX:G1MixedGCLiveThresholdPercent=85

  • 一个old region的内存占用率达到该阈值时,这个old region就被视为可回收区域(垃圾区域),默认占用率为85%。
  • Mixed GC中,一个old region空间最多被回收的百分比也为该值。

 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 -XX:G1OldCSetRegionLiveThresholdPercent setting.

-XX:G1HeapWastePercent=5

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%。

  • 在全局标记结束后能够统计出所有Cset内可被回收的垃圾占整对的比例值,如果超过5%,那么就会触发之后的多轮Mixed GC,如果不超过,那么会在之后的某次Young GC中重新执行全局并发标记。
  • 可以尝试适当的调高此阈值,能够适当的降低Mixed GC的频率

-XX:G1MixedGCCountTarget=8

设置在一次全局并发标记之后执行Mixed GC的最大次数,默认最多8次。

Sets the target number of mixed garbage collections after a marking cycle to collect old regions with at most G1MixedGCLIveThresholdPercent live data. The default is 8 mixed garbage collections. The goal for mixed collections is to be within this target number.Footref1

-XX:G1OldCSetRegionThresholdPercent=10

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

-XX:G1ReservePercent=10

  • Sets the percentage of reserve memory to keep free so as to reduce the risk of to-space overflows. The default is 10 percent. When you increase or decrease the percentage, make sure to adjust the total Java heap by the same amount.Footref1
  • Sets the amount of heap that is reserved as a false ceiling to reduce the possibility of promotion failure. The default value is 10.

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。

下一代收集器:

新一代垃圾回收器ZGC的探索与实践 - 美团技术团队

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JVM (Java Virtual Machine) G1 (Garbage-First) 垃圾收集器是一种用于 Java 应用程序的垃圾收集算法。它是自JDK 7u4版本后引入的一种全新的垃圾收集器G1垃圾收集器的设计目标是为了解决传统的分代垃圾收集器可能遇到的一些问题,如停顿时间长、内存碎片化等。它采用了一种基于区域的垃圾收集方式,可以将内存划分为多个大小相等的区域,每个区域可以是Eden、Survivor或Old区。 G1垃圾收集器的工作原理如下: 1. 初始标记(Initial Mark):标记所有从根对象直接可达的对象。 2. 并发标记(Concurrent Mark):在并发执行程序的同时,标记那些在初始标记阶段无法访问到的对象。 3. 最终标记(Final Mark):为并发标记阶段发生改变的对象进行最终标记。 4. 筛选回收(Live Data Counting and Evacuation):根据各个区域的回收价值来优先回收价值低的区域。 G1垃圾收集器具有以下特点: - 并发执行:在执行垃圾收集过程时,尽可能减少应用程序的停顿时间。 - 分区回收:将整个堆划分为多个区域,可以根据需要优先回收垃圾较多的区域,从而避免全堆回收带来的长时间停顿。 - 内存整理:G1垃圾收集器会对内存进行整理,减少内存碎片化,提高内存利用率。 需要注意的是,G1垃圾收集器并不适用于所有情况。在特定的场景下,如大堆情况下的长时间运行、对延迟要求非常高的应用等,可能需要考虑其他垃圾收集器的使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值