JVM知识总结(G1收集器)

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

文章收录在网站:http://hardyfish.top/

在这里插入图片描述

G1收集器

G1**(Garbage First)是一款面向服务器的垃圾收集器,主要针对配置多核处理器以及大容量内存的机器,满足GC停顿时间要求的同时,还具备高吞吐量性能特征**。

  • JDK 9 开始默认使用G1 垃圾收集器

内存划分

G1将堆划分为多个大小相等的独立的Region区域。

一般Region区的大小等于堆空间的总大小除以2048,比如目前的堆空间总大小为8GB,就是8192MB/2048=4MB,那么最终每个Region区的大小为4MB

  • 也可以用参数-XX:G1HeapRegionSize强制指定每个Region区的大小。

新生代和老年代

默认新生代对堆内存的初始占比是5%,如果堆大小为8GB,那么年轻代占据400MB左右的内存,对应大概是100个Region区,可以通过-XX:G1NewSizePercent设置新生代初始占比。

在Java程序运行中,JVM会不停的给新生代增加更多的Region区,但是最多新生代的占比不会超过堆空间总大小的60%,可以通过-XX:G1MaxNewSizePercent调整。

新生代中的Eden区和Survivor区对应的Region区比例也跟之前一样,默认8:1:1,假设新生代现在有400个Region,那么整个新生代的占比则为Eden=320,S0/From=40,S1/To=40

G1中的年老代晋升条件和之前的无差,达到年龄阈值的对象会被转入年老代的Region区中,不同的是对于大对象的分配,在G1中不会让大对象进入年老代,在G1中由专门存放大对象的Region区叫做Humongous区,如果在分配对象时,判定出一个对象属于大对象,那么则会直接将其放入Humongous区存储。

在G1中,判定一个对象是否为大对象的方式为:

对象大小是否超过单个普通Region区的50%,如果超过则代表当前对象为大对象,那么该对象会被直接放入Humongous区。

  • 比如:目前是8GB的堆空间,每个Region区的大小为4MB,当一个对象大小超过2MB时则会被判定为属于大对象。

如果程序运行过程中出现一个巨型对象,当一个Humongous区存不下时,可能会横跨多个Region区存储它。

Humongous区存在的意义:

可以避免一些短命的巨型对象直接进入年老代,节约年老代的内存空间,可以有效避免年老代因空间不足时的GC开销。

当堆空间发生全局GC(FullGC)时,除开回收新生代和年老代之外,也会对Humongous区进行回收。

什么场景下适合采用G1收集器的建议

堆空间内50%以上的内存会被存活占用的应用。

分配速度和晋升速度特别快的应用。

至少8GB以上堆内存的应用。

采用原本分代收集器GC时间会长达1s+的应用。

追求停顿时间在500ms以内的应用。

GC类型

YoungGC:

在G1中,当新生代区域被用完时,G1首先会大概计算一下回收当前的新生代空间需要花费多少时间,如果回收时间远远小于参数-XX:MaxGCPauseMills设定的值,那么不会触发YoungGC,而是会继续为新生代增加新的Region区用于存放新分配的对象实例。

  • 用户未显式通过-XX:MaxGCPauseMills参数设定GC预期回收停顿时间值,那么G1默认为200ms

直至某次Eden区空间再次被放满并经过计算后,此次回收的耗时接近-XX:MaxGCPauseMills参数设定的值,那么才会触发YoungGC

YoungGC被触发时,首先会将目标Region区中的存活对象移动至幸存区空间(Survivor-From区标志的Region)。

同时达到晋升年龄标准的对象也会被移入至年老代Region中存储。

  • G1收集器在发生YoungGC时,复制移动对象时是采用的多线程并行复制,以此来换取更优异的GC性能。

MixedGC:

当整个堆中年老代的区域占有率达到参数-XX:InitiatingHeapOccupancyPercent设定的值后触发MixedGC,发生该类型GC后,会回收所有新生代Region区、部分年老代Region区(会根据期望的GC停顿时间选择合适的年老代Region区优先回收)以及大对象Humongous区。

正常情况下,G1垃圾收集时会先发生MixedGC,主要采用复制算法,在GC时先将要回收的Region区中存活的对象拷贝至别的Region区内,拷贝过程中,如果发现没有足够多的空闲Region区承载拷贝对象,此时就会触发一次Full GC

FullGC:

当整个堆空间中的空闲Region不足以支撑拷贝对象或由于元数据空间满了等原因触发,在发生FullGC时,G1首先会停止系统所有用户线程,然后采用单线程进行标记、清理和压缩整理内存,以便于清理出足够多的空闲Region来供下一次MixedGC使用。

但该过程是单线程串行收集的,因此这个过程非常耗时(ShenandoahGC中采用了多线程并行收集)。

  • G1收集器中并没有FullGC,,G1中的FullGC是采Sserial old FullGC。

GC过程

在这里插入图片描述

G1收集器在发生GC时执行过程大致会分为四个步骤(主要指MixedGC):

初始标记(InitialMark):

  • 先触发STW,然后使用单条GC线程快速标记GCRoots直连的对象。

并发标记(ConcurrentMarking):

  • 与CMS的并发标记过程一致,采用多条GC线程与用户线程共同执行,根据Root根节点标记所有对象。

最终标记(Remark):

  • 同CMS的重新标记阶段(也会STW),主要是为了纠正并发标记阶段因用户操作导致的错标、误标、漏标对象。

筛选回收(Cleanup):

  • 先对各个Region区的回收价值和成本进行排序,找出 回收价值最大 的Region优先回收。
  • 筛选回收阶段在G1收集器中是会停止所有用户线程后,采用多线程并行回收的。

假设此时年老代空间共有800Region区,并且都满了,所以此刻会触发GC。

但根据GC的预期停顿时间值,本次GC只能允许停顿200ms,而G1经过前面的成本计算后,大致可推断出:

  • 本次GC回收600Region区恰好停顿时间可控制在200ms左右,那么最终就会以 回收600Region区 为基准触发GC,这样则能尽量确保GC导致的停顿时间可以被控制在我们指定的范围之内。

G1会在后台维护着一个优先列表:

  • CollectionSet(CSet),它记录了GC要收集的Region集合,集合里的Region可以是任意年代的。

在G1中回收算法都是采用复制算法,都会将一个Region区中存活的对象复制到另外一个Region区内。

G1缺点:

G1需要记忆集 (卡表)来记录新生代和老年代之间的引用关系。

  • 这种数据结构在 G1 中需要占用大量的内存,可能达到整个堆内存容量的 20% 甚至更多。
  • 而且 G1 中维护记忆集的成本较高,带来了更高的执行负载,影响效率。

CMS 在小内存应用上的表现要优于 G1,而大内存应用上 G1 更有优势,大小内存的界限是6GB到8GB。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值