JVM垃圾回收(四)

4、G1垃圾收集器(重点)

G1垃圾收集器是jdk1.7中正式使用的全新的垃圾收集器,oracle官方计划在jdk9中将G1垃圾收集器变成默认的垃圾收集器,以替代CMS。

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

  1. 开启G1垃圾收集器
  2. 设置堆的最大内存
  3. 设置最大的停顿时间

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

4.1、原理

G1垃圾收集器相对比其他收集器而言,最大的区别在于他取消了年轻代和老年代的物理划分,取而代之的是将对划分成为若干个区域(Region),这些区域中包含了逻辑上的年轻代、老年代区域。

这样做的好处就是,我们再也不用单独的空间对每个代进行设置了,不用担心每个代内存是否足够。
在这里插入图片描述
在这里插入图片描述
在G1划分的区域中,年轻代的垃圾收集器依然采用暂停所有应用现成的方式,将存活对象拷贝到老年代或者Survivor空间,G1垃圾收集器通过将对象从一个区域复制到另一个区域,完成清理工作。

这就意味着,在正常处理过程中,G1完成了对的压缩(至少是部分堆的压缩),这样也就不会有CMS内存碎片的问题存在了。

在G1中,有一种特殊的区域,叫Humongous区域。

  • 如果一个对象占用的空间超过了分区容量的50%以上,G1收集器就认为这是一个巨星对象。
  • 这些巨型对象,默认直接会被分配在老年代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。
  • 为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨星对象。如果一个H区装不下一个巨星对象,那么G1会寻找一个连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。

4.2 Yong GC

Yong GC主要是对Eden区进行GC,它在Eden空间耗尽时会被触发。

  • Eden空间的数据移动到Survivor空间中,如果Survivor空间不够,Eden空间的部分数据会直接晋升到年老代空间。
  • Survivor区的数据移动到新的Survivor区中,也有部分数据晋升到年老代空间中。
  • 最终Eden空间的数据为空,GC停止工作,应用线程继续执行。

在这里插入图片描述
在这里插入图片描述

4.2.1 Remembered Set(已记忆集合)

在GC年轻代的对象时,我们如何找到年轻代中对象的根对象呢?
根对象可能是在年轻对象中,也可以在老年代中,那么老年代中的所有对象都是根吗?
如果全量扫描老年代,那么这样扫描下来会耗费大量的时间。
于是,G1引进了RSet的概念,全程是Remembered Set,起作用是跟踪指向某个堆内的对象引用。
在这里插入图片描述
每个Region初始化时,会初始化一个RSet,该集合用来记录并跟踪其他Region指向该Region中对象的引用,乜咯Region默认按照512kb划分成多个Card,所以RSet需要记录的东西应该是xx Region的xx Card。

由上图可看出,Region1、Region2以及Region3中分别有1、2、1个对象,每个Region中有对应的RSet,来记录他们的引用情况,
Region1和Region3中的对象分别引用了Region2中的对象,那么Region2中的RSet则记录了Region1和Region3引用的信息(红
色部分),这样就不需要扫描全部了,只需要扫描他的RSet集合即可。

4.3 Mixed GC

当越来越多的对象晋升到老年代old region时,为了避免堆内存被耗尽,虚拟机会触发一个混合的垃圾收集器,即Mixed GC,该算法并不是一个Old GC,除了回收整个Yong Region,还会回收一部分的Old Region,这里需要注意:是一部分老年代,而不是全部的老年代,可以选择哪些Old Region进行手机,从而可以对垃圾回收的耗时进行控制,也要注意Mixed GC并不是Full GC。

Mixed GC什么时候触发?由参数-XX:InitiatingHeapOccupancyPercent=n决定。默认:45%,该参数的意思是:当老年代大小占整个堆大小百分比达到阈值时触发。

它的步骤分2步:

  1. 全局并发标记(global concurrent marking)
  2. 拷贝存活对象(evacuation)
4.3.1 全局并发标记

全局并发标记,执行分为五个步骤:

  • 初始标记(initial mark, STW)
    • 标记从根节点直接可达的对象,这一阶段会执行一次年轻代的GC,会产生全局停顿。
  • 跟区域扫描(root region scan)
    • G1 GC在初始标记的存活扫描对老年代的引用,并标记被引用的对象
    • 该阶段与应用程序(非STW)同时运行,并且只有完成该阶段后,才能开始下一次STW年轻代垃圾回收
  • 并发标记(Concurrent Marking)
    • G1 GC在整个对重查找可访问的(存活的)对象。该阶段与应用程序同事运行,可以被STW年轻代垃圾回收终端。
  • 重新标记(Remark, STW)
    • 该阶段是STW回收,因为程序在运行,针对上一次的标记进行修正。
  • 清楚垃圾(Cleanup,STW)
    • 清点和重置标记状态,该阶段会STW,这个阶段并不会实际上去做垃圾的手机,等待evacuation阶段来回收。
4.3.2、拷贝存活对象

Evacuation阶段是全暂停的。该阶段把一部分Region里面的活体对象拷贝到另一部分Region中,从而实现垃圾的回收处理。

4.4、G1收集器相关参数

  • -XX:+UseG1GC 使用G1垃圾收集器
  • -XX:MaxGCPauseMills 设置期望达到的最大GC停顿时间指标(JVM会尽力实现,但不保证达到),默认值是200ms
  • -XX:G1HeapRegionSize=n 设置G1区域的大小。值是2的幂,范围是1MB到32MB。目标是根据最小的Java堆大小划分出约2048个区域。默认的堆内存是1/2000.
  • -XX:ParallelGCThreads=n 设置STW工作线程数的值。将n的值设置为逻辑处理器的数量。n的值与逻辑处理器的数量系统,最多为8。
  • -XX:ConcGCThreads=n 设置并行标记的线程数。将n设置为并行垃圾回收线程数(ParallelGCThreads)的1/4左右。
  • -XX:InitiatingHeapOccupancyPercent=n 设置触发标记周期的Java堆占用率阈值。默认占用率是整个Java堆的45%。

4.5、测试

-XX:+UseG1GC  -XX:MaxGCPauseMillis=100  -XX:+PrintGCDetails -Xmx256m
打印日志:
[GC pause (G1 Evacuation Pause) (young), 0.0078388 secs]
   [Parallel Time: 6.4 ms, GC Workers: 8]
      [GC Worker Start (ms): Min: 641.2, Avg: 643.6, Max: 647.2, Diff: 6.1]
      # 扫描根节点
      [Ext Root Scanning (ms): Min: 0.0, Avg: 1.1, Max: 6.0, Diff: 6.0, Sum: 8.8]
      # 更新RS区域所消耗的时间
      [Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
         [Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.1]
      # 对象拷贝
      [Object Copy (ms): Min: 0.0, Avg: 2.4, Max: 5.0, Diff: 5.0, Sum: 19.1]
      [Termination (ms): Min: 0.0, Avg: 0.2, Max: 0.3, Diff: 0.3, Sum: 1.7]
         [Termination Attempts: Min: 1, Avg: 1.3, Max: 2, Diff: 1, Sum: 10]
      [GC Worker Other (ms): Min: 0.1, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 0.9]
      [GC Worker Total (ms): Min: 0.2, Avg: 3.8, Max: 6.3, Diff: 6.1, Sum: 30.7]
      [GC Worker End (ms): Min: 647.4, Avg: 647.4, Max: 647.4, Diff: 0.0]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.4 ms] # 清空CardTable
   [Other: 1.1 ms]
      [Choose CSet: 0.0 ms] # 选取CSet
      [Ref Proc: 0.5 ms] # 弱引用、软引用的处理耗时
      [Ref Enq: 0.0 ms] # 弱引用、软引用的入队耗时
      [Redirty Cards: 0.4 ms]
      [Humongous Register: 0.0 ms] # 大对象区域注册耗时
      [Humongous Reclaim: 0.0 ms] # 大对象区域回收耗时
      [Free CSet: 0.0 ms]
   # 年轻代的大小统计
   [Eden: 4096.0K(4096.0K)->0.0B(6144.0K) Survivors: 0.0B->1024.0K Heap: 4096.0K(16.0M)->1965.5K(16.0M)]
 [Times: user=0.09 sys=0.00, real=0.01 secs] 

4.6、对于G1垃圾收集器优化建议

  • 年轻代大小
    • 避免使用-Xmn选项或-XX:NewRatio等其他相关选项显式设置年轻代大小
    • 固定年轻代的大小会覆盖暂停时间目标
  • 暂停时间不要太过严苛
    • G1 GC的吞吐量目标是90%的应用程序时间和10%的垃圾回收时间
    • 评估G1 GC的吞吐量时,暂停时间不要太过严苛。目标太过严苛表示你愿意承受更多的垃圾回收开销,这会直接影响到吞吐量。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值