Java垃圾收集器-G1收集器

概述
英文全名:Garbage First(G1)

为什么发布这款收集器

  • 业务越来越庞大、复杂,用户越来越多,GC是应用程序正常运行的保障,经常造成STW的GC无法满足现代的需求,需要不断的去尝试优化。

  • 硬件水平的提升,内存和处理器数量。

G1设定的目标

  • 在延迟可控的情况下获得尽可能高的吞吐量,担当“全功能收集器”的重任。

简单介绍

  • G1是一款面向服务端应用的垃圾收集器,主要针对配备多核CPU及大容量内存的机器,以极高概率满足GC停顿时间的同时,还兼容高吞吐量的性能特征。
  • JDK1.7版本正式启用,移除了Experimental标识,JDK9以后的默认垃圾收集器,取代了CMS回收器以及Parallel+Parallel Old组合。
  • CMS在JDK9被标记废弃,在JDK8中可以使用-XX:+UseG1GC来启用。
  • G1使用了全新的分区算法。

主要思路

G1是一个并行回收器,把堆内存分割未很多不相关的区域(Region),使用不同的Region来表示Eden,幸存区0区,幸存区1区,老年代等。G1避免针对全堆进行垃圾收集,G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。

优势

  • 兼具并行与并发
    • 并行性:G1在回收期间,可以有多个GC线程同时工作
    • 并发性:G1可以与应用程序交替执行,部分工作可以与应用程序同时执行。

 

  • 分代收集
    • 从分代上看,G1仍是属于分代型垃圾收集器,它区分年轻代和老年代。但从堆结构上看,它不要求整个Eden区、年轻代或者老年代都是连续的,也不再坚持固定大小和固定数量。
    • 将堆空间分为若干个区域(Region),这些区域中包含逻辑上的年轻代和老年代。
    • 和之前各类收集器不同,它同时兼顾年轻代和老年代。

 

  • 空间整合
    • G1的内存回收以region为基本单位,Region之间使用复制算法,但整体上实际可看作是标记-整理算法,可避免内存碎片,利于程序的长时间运行。
  • 可预测的停顿时间模型

G1可以明确指定在M毫秒的时间范围内进行垃圾回收。

      • 基于分区原因,可以选取部分区域进行内存回收。
      • G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region,保证最低的停顿时间。

缺陷

  • 相对比CMS,在用户程序运行期间,G1为了垃圾收集产生的内存占用还是程序运行时的额外执行负载都要比CMS高。
  • G1在大内存应用上可发挥优势,平衡点在6-8G之间,在小内存应用上CMS的表现大概率优于G1。

G1收集器相关参数设置

  • -XX:+UseG1GC    手动指定使用G1收集器
  • -XX:G1HeapRegionSize    设置每个Region的大小。值是2的幂,范围是1MB到32MB之间,目标是根据最小的java堆大小划分出约2048个区域,默认是堆内存的1/2000.
  • -XX:MaxGCPauseMillis    设置期望达到的最大GC停顿时间指标(尽量实现,不保证达到),默认值时200ms
  • -XX:ParallelGCThreads    设置STW工作线程数的值,最多设置为8
  • -XX:ConcGCThreads    设置并发标记的线程数,将n设置为并行垃圾回收线程数(ParallelGCThreads)的1/4左右。
  • -XX:InitiatingHeapOccupancyPercent    设置触发并发GC周期的java堆占用率阈值,超过此值,就触发GC,默认值时45

G1收集器常见操作步骤

G1的设计原则就是简化JVM性能调优,开发人员只需三步即可完成调优:

第一步:开启G1垃圾收集器

第二步:设置堆的最大内存

第三步:设置最大的停顿时间

G1中提供了三种垃圾回收模式:Young GC、Mixed GC和Full GC,在不同的条件下被触发。

使用场景

  • 面向服务端应用,针对具有大内存、多处理器的机器。(在普通大小的堆里表现并不好)
  • 最主要应用是需要低GC延迟,并具有大堆的应用程序提供解决方案
  • 用来替换掉CMS收集器

在下面情况下,可考虑使用G1替换CMS:

1. 超过50%的java堆被活动数据占用;

2. 对象分配频率或年代提升频率变化很大;

3. GC停顿时间过长(长于0.5至1s).

  • HotSpot的垃圾收集器中,除了G1,其他垃圾收集器都是使用内置的JVM线程执行GC的多线程操作,而G1可以采用应用线程承担后台运行的GC工作,以协助加速垃圾收集过程。

分区Region

  • 一个region只能属于一个角色(eden、survivor、old、humongous(大对象))

G1收集器垃圾回收过程

主要包含如下三个环节:

  • 年轻代GC(Young GC)
  • 老年代并发标记过程(Concurrent Marking)
  • 混合回收(Mixed GC)

如果需要,单线程、独占式、高强度的Full GC还是会继续存在的。它针对GC的评估失败提供一种失败保护机制。

主要过程概括:

  1. 当年轻代的Eden区用尽时开始年轻代回收过程,G1的年轻代收集阶段是一个并行的独占式收集器,G1暂停所有应用程序线程,启动多线程执行年轻代回收。
  2. 当堆内存使用达到一定值(默认45%)时,开始老年代并发标记过程。
  3. 标记完成马上开始混合回收过程。G1的老年代回收器不会进行整个老年代的回收,一次只需要扫描/回收一小部分老年的Region就可以了。

G1回收过程一:年轻代GC

年轻代垃圾回收只会回收Eden区和Survivor区。

YGC时,G1首先停止应用程序的执行,G1创建回收集,主要记录被回收的Region的集合。

G1回收过程二:并发标记过程

初始标记

根区域扫描

并发标记

再次标记

独占清理

并发清理

G1回收过程三:混合回收

当越来越多的对象晋升到老年代old region时,为了避免堆内存被耗尽,会触发一次混合回收。

G1回收器优化建议

年轻代大小

  • 避免使用-Xmn或-XX:NewRatio等相关选项显示设置年轻代大小
  • 固定年轻代的大小会覆盖暂停时间目标

暂停时间目标不要太过严苛

  • G1的吞吐量目标是90%的应用程序时间和10%的垃圾回收时间,评估G1的吞吐量时,目标太过严苛则表示需要承受更多的垃圾回收开销,这些会直接影响吞吐量。

 


关于作者

justin
获得点赞
文章被阅读