首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

G1的收集日志,理解GC过程

测试代码

代码的jvm参数:-verbose:gc -Xms10m、-Xmx10m、-XX:+UseG1GC、-XX:+PrintGCDetails、-XX:+PrintGCDateStamps、-XX:+PrintGCTimeStamps、-XX:MaxGCPauseMillis=200m;

重要参数详解:

-XX:+UseG1GC:由于是jdk8所以需要指定使用G1收集器;

-XX:+PrintGCDateStamps:表示打印GC日志的系统时间;

-XX:+PrintGCTimeStamps:打印JVM启动的时候的相对时间;

-XX:MaxGCPauseMillis=200m:是G1中最重要的参数之一,表示期望GC过程中停顿的时间,这里表示设置200ms

G1收集器只用指定最大最小堆,不用指定新生代大小,由G1收集器自动分配更好!

代码如下图:

每个数组是1M,数组也会分布到堆中,其中createOneM()方法创造的1M数组由于是方法,在方法执行完成后,下次GC的时候这个数组会被回收,而其他数组不会被回收。

GC日志详解

这段代码的GC日志较长,所以进行分段分析。

第一段GC日志如下图:

第一块红框内参数详解:

2020-04-16T15:59:17.614+0800: 0.158:系统时间,0.158表示想到JVM启动时间;

GC:GC标识;

pause:表示暂停了用户线程;

G1 Humongous Allocation:括号表示触发GC的原因,G1中有Humongous区域,对象占用内存大于Region内存一半都会存入Humongous区,这里Region内存大小是1M(最后一步能看到)。

young:表明是Young GC;

initial-mark:初始标记;

第二块红框就是Young GC过程,主要过程如下:

◆[Parallel Time: 0.7 ms, GC Workers: 4]:表示并行用时0.7ms,4个并行线程;

详细Young GC 过程:Ext Root Scanning(根扫描)、Update RS(更新RS)、Scan RS(处理RS)、Code Root Scanning(code root扫描,code root是JIT编译后的代码里引用了heap中的对象)、Object Copy(对象拷贝)、GC Worker Other(GC线程其他花费时间)、GC Worker Total(4条GC线程总时间)、GC Worker End(最快、最慢GC线程结束时间,是相对启动时间的);

第三个红框内容详解:

Code Root Fixup、Code Root Purge:修复和清除Code Root;

Clear CT:清除card tables 中的dirty card;

Other:其他处理,比如选择CSet、处理引用队列(YGC第五阶段)、释放CSet;

最后一个红框:

YGC完成最后展示各个空间GC的内存变化,首先Eden区内存被清空,同时Eden区原来大小是4096K,GC后变成了3072K,说明G1对Eden进行了调整。同时Survivors由0变成了1024K,总共堆使用由4352到1787,说明清理了。

全局并发标记

在YGC完后后紧接着就进行了全局并发标记过程,日志如下图:

主要分如下几个步骤:concurrent-root-region-scan-start(根区域扫描)、concurrent-mark-start(并发标记)、remark(重新标记)、cleanup(清除垃圾),其中initial-mark(初始标记)在YGC开始的时间已经执行完成。

再次GC

从上面那张图看到清理完成后有进行了GC,详情如下图:

这次GC有点不同的是在young后面加了一个to-space exhausted(空间耗尽)标识,还有一个是在other中多出了一个步骤Evacuation Failure(晋升失败),并且他花费了0.6ms,是这个过程花费最长的而且是长很多的。

我们先看看GC的结果,Eden区使用由1024变成了0,Survivor也是由1024K变成了0,堆总体使用基本无变化,说明Eden区的对象并没有进入Survivor而是直接进入了老年代,这里就对应了Evacuation Failure

最终结果

这个整个GC还有好几次,不过过程都差不多,直接看最后结果,日志如下图:

经历过几次GC后,可以看到最后一次YGC几乎没有回收任何内存,所以最后不得不进行了一次Full GC。最后看堆分配总共10240K,使用4714K。region size 1024K表示Region大小是1024K,1 young (1024K)表示1个young Region 占用内存1024K,,0 survivors (0K)表示0个survivors。

总结

学习了G1的理论还要真正的实例来证明才能真正吸收,当然现在线上真实环境很少能接触到,这里通过一个简单的例子来实现了G1的几个过程,验证了之前的理论学习,尤其其中几个点:

1、新生代的不断调整,可以看出G1在GC过程中会不断的调整Eden的大小,同时发现日志中并没有体现survivor的大小,只显示了使用大小,说明这个也是动态变化的,使用了多少就算多少。

2、Evacuation Failure,发现占用的时间特别多,直译过来是晋升失败,类似于CMS里面的晋升失败,堆空间的垃圾太多导致无法完成Region之间的拷贝,于是不得不退化成Full GC来做一次全局范围内的垃圾收集。

3、G1最终的GC还是Full GC,当正常的GC不满足需求的时候就会触发Full GC。

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200416A0Z08800?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券