java中的G1回收器怎么用

发布时间:2021-09-27 09:55:41 作者:柒染
来源:亿速云 阅读:132

这篇文章给大家介绍java中的G1回收器怎么用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

G1 回收器

G1回收器是在jdk1.7中正式使用的全新垃圾回收器,并且是jdk9及之后版本的默认回收器。从分代上看,G1 依然属于分代垃圾回收器,它会区分年轻代和老年代,依然有eden区和survivor区,但从堆的结构上看,它并不要求整个eden区、年轻代或者老年代都连续。G1使用了全新的分区算法,特点如下:

1 G1的内存划分和主要收集过程

G1将堆进行分区,划分为一个个的区域,每次回收时,只回收其中几个区域,以此来控制垃圾回收产生的一次停顿时间。

G1的回收过程可能有4个阶段:

2. G1的新生代GC

新生代GC的主要工作是回收eden区和survivor区。一旦eden区被占满,新生代GC就会启动。新生代GC只处理eden区和survivor区,回收后所有的eden区都应该被清空,而survivor区会被回收一部分数据。

3. G1 的并发标记周期

G1 的并发阶段和 CMS 有点类似,它们都是为了降低一次停顿时间,而将可以和应用程序并发的部分单独提取出来执行。

并发标记周期可以分为以下几步:

除了初始标记重新标记独占清理,其他几个阶段都可以和应用程序并发执行。

在并发标记周期中,G1会产生如下日志:

3.1 初始标记,它伴随着一次新生代GC
[GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0014636 secs]
   ...
   [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
 [Times: user=0.01 sys=0.00, real=0.00 secs]
3.2 一次并发的根区域扫描,并发扫描过程中不能被新生代GC中断。
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0003832 secs]
3.3 并发标记,并发标记可以被新生代GC打断,下面的日志显示了一次并发标记被3次新生代GC打断。
[GC concurrent-mark-start]
[GC pause (young), 0.0003382 secs]
...
  [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
[Times: user=0.01 sys=0.00, real=0.00 secs] 
...
  [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
[Times: user=0.01 sys=0.00, real=0.00 secs] 
...
  [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
[Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC concurrent-mark-end, 0.0003929 secs]
3.4 重新标记:是会引起全局停顿的,它的日志如下:
[GC remark [Finalize Marking, 0.0006027 secs] [GC ref-proc, 0.0000295 secs] [Unloading, 0.0003390 secs], 0.0010737 secs]
 [Times: user=0.01 sys=0.00, real=0.01 secs]
3.5 重新标记后会进行独占清理,独占清理会重新计算各个区域的存活对象,并以此可以得到每个区域进行GC的效果,它的日志如下:
[GC cleanup 10M->10M(40M), 0.0003016 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs]
3.6 并发清理,是并发执行的,它会根据独占清理阶段计算得出每个区域的存活对象数量,直接回收不包含存活对象的区域。它的日志如下:
[GC concurrent-cleanup-start]
[GC concurrent-cleanup-end, 0.0000016 secs]

4. 混合回收

在并发标记周期中,虽然有部分对象被回收,但是总体上说,回收的比例是相当低的。但是在并发标记周期后,G1已经明确知道哪些区域含有比较多的垃圾对象,在混合回收阶段就可以专门针对这些区域进行回收。这个阶段叫做混合回收,是因为这个阶段既会执行正常的年轻代GC,又会选取一些被标记的老年代区域进行回收,它同时处理了新生代和老年代

混合GC会产生如下日志:

[GC pause (mixed), 0.0003382 secs]
...
  [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2624.1K(40.0M)]
[Times: user=0.01 sys=0.00, real=0.00 secs]

混合GC会执行多次,走到回收了足够多的内存空间,然后它会触发一次新生代GC。新生代GC后,又可难会发生一次并发标记周期的处理,最后又会引起混合GC的执行。

5. 必要时的Full GC

和CMS类似,并发回收由于让应用程序和GC线程交替工作,总是不能完全避免在特别繁忙的场合出现在回收过程中内存不充足的情况。当遇到这种情况时,G1也会转入一个FullGC。

当G1在并发标记时,由于老年代被快速填充,G1会终止并发标记而转入一个Full GC:

[GC concurrent-mark-start]
[Full GC 898->896(900M), 0.7003382 secs]
  [Eden: 0K(45.0M)->0.0B(45.0M) Survivors: 0.0B->0B Heap: 898.7M(900.0M)->896.2M(900.0M)]
[Times: user=1.01 sys=0.00, real=0.075 secs] 
[GC concurrent-mark-abort]

此外,如果在混合GC时空间不足,或者在新生代GC时survivor区和老年代无法容纳幸存对象,都会导致一次FullGC.

6. G1的日志

# 表示应用程序发生了一次新生代GC,这是在初始标记时发生的,耗时0.0018193秒,意味着程序至少暂停了0.0018193秒
[GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0018193 secs]
   # 后续并行时间,表示所有GC线程总的花费时间,这里为0.9毫秒,workers为8表示有8个GC线程
   [Parallel Time: 0.9 ms, GC Workers: 8]
      # GC线程的执行情况,这里统计了8个线程的统计值,如 平均、最小、最大和差值(最大值与最小值之差),
      # 106.6 表示在应用程序启动 106.6 毫秒后,启动了该GC线程
      [GC Worker Start (ms): Min: 106.6, Avg: 106.7, Max: 106.7, Diff: 0.1]
      # 根扫描时间的统计值
      [Ext Root Scanning (ms): Min: 0.4, Avg: 0.4, Max: 0.5, Diff: 0.1, Sum: 3.3]
      # 更新记忆集(Remember Set)的耗时。
      # 记忆集是G1中维护的一个数据结构,简称RS。每一个G1区域都有一个RS与之关联。由于G1回收时是按照区域
      # 回收的,比如在回收区域A的对象时,很可能并不回收区域B的对象,为了回收区域A的对象,要扫描区域B甚
      # 至整个堆来判定区域A中哪些对象不可达,这样做的代价显然很大。因此,G1在区域A的RS中,记录了在区域
      # A中被其他区域引用的对象,这样在回收区域A时,只要将RS视为区域A根集的一部分即可,从而避免做整个堆
      # 的的扫描。由于系统在运行过程中,对象之间的引用关系是可能时刻变化的,为了更高效地跟踪这些引用关系,
      # 会将这些变化记录在Update Buffers中。这里的Processed Buffers指的就是处理这个Update Buffers数据。
      [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]
      # 扫描RS的时间 
      [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.0, Diff: 0.0, Sum: 0.0]
      # 在正式回收前,G1 会对被回收区域的对象进行疏散,即将存活对象放置在其他区域中,因此需要进行对象复制
      [Object Copy (ms): Min: 0.2, Avg: 0.3, Max: 0.4, Diff: 0.2, Sum: 2.2]
      # 给出GC工程线程终止的信息,这里的终止时间是线程花在终止阶段的耗时。在GC线程终止前,它们会检查其
      # 他GC线程的工作队列,查看是否仍然还有对象引用没有处理完,如果其他线程仍然有没有处理完的数据,请求
      # 终止的线程会帮助它尽快完成,随后再尝试终止。其中,Termination Attempts 展示了工作线程的终止次数。
      [Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 1.0]
         [Termination Attempts: Min: 1, Avg: 2.9, Max: 6, Diff: 5, Sum: 23]
      # 显示GC线程花费在其他任务中的耗时
      [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [GC Worker Total (ms): Min: 0.8, Avg: 0.8, Max: 0.9, Diff: 0.1, Sum: 6.6]
      # GC 工作线程的完成时间
      [GC Worker End (ms): Min: 107.5, Avg: 107.5, Max: 107.5, Diff: 0.0]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   # 显示清空 CardTable的时间,RS 就是依靠CardTable来记录哪些是存活对象的
   [Clear CT: 0.1 ms]
   # 显示其他几个任务的耗时,比如选择CSet(Collection Sets,表示被选取的、将要被回收的区域的集合)的时
   # 间、Ref Proc(处理弱引用、软引用的时间)、Ref End(弱引用、软引用入队时间)和Free CSet(释放被
   # 回收的CSet中区域的时间,包括它们的RS)
   [Other: 0.8 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.7 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.1 ms]
      [Humongous Register: 0.0 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 0.0 ms]
   [Eden: 2048.0K(14.0M)->0.0B(13.0M) Survivors: 0.0B->1024.0K Heap: 13.8M(40.0M)->2656.1K(40.0M)]
 [Times: user=0.00 sys=0.00, real=0.00 secs]

7. 相关的参数

关于java中的G1回收器怎么用就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

推荐阅读:
  1. 垃圾回收(4)G1的GC过程
  2. 垃圾回收(3)G1的结构和概念

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:java中如何使用mat分析java堆

下一篇:ServletContext.getRealPath()输入参数要以”/”开头的示例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》