G1垃圾收集器

来源:互联网 发布:炽阳魔盒软件下载 编辑:程序博客网 时间:2024/06/05 17:11

文章转自个人博客:http://wangdingkun.com/2017/09/22/G1垃圾收集器/

Garbage-First GC概述

       Garbage-First(G1)垃圾收集器是一款低延迟且停顿时间可控的server端垃圾收集器;它适用于多核大内存的服务器运行环境,GC停顿时间不会随着堆栈及存活对象的增长而增长。G1收集器是CMS的替代。

停顿可控

       与CMS一样,G1也是一款低延迟垃圾收集器;与CMS不同的是G1的GC暂停时间是可控的,我们可以在应用启动时通过MaxGCPauseMillis指定最大停顿时间,G1会尽可能满足这个目标,它是怎么做到的呢?
       G1把堆划分为很多小区域(region)来组织,每个区域是一段连续的内存区间,在垃圾回收的时有一个全局标记阶段,在标记结束后G1知道每个region的垃圾占用情况,它根据最大停顿时间来决定回收垃圾最多的一个或多个region。

备注:G1会尽量满足MaxGCPauseMillis指定的停顿时间,但不一定能达到目标

内存压缩

       回收regions时,G1会选择一块region,把被回收region中的存活对象拷贝到新region中。与CMS不同的是它不会留下内存碎片(G1采用复制算法,CMS采用标记-清除算法?),同样整个过程是并发进行。

  • CMS采用标记-清除算法,会产生内存碎片,提供了参数-XX:+UseCMSCompactAtFullCollection来控制在Full GC时是否进行内存碎片整理,虽然解决了碎片问题,但是Full GC整个阶段时间比较长;-XX:CMSFullGCsBeforeCompaction指定执行多少次不压缩的Full GC后,来一次带压缩的Full GC,默认是0表示每次Full GC都要执行压缩。
  • Parallel会对整个堆执行压缩,停顿时间长

用G1替换CMS

使用CMS出现以下情况时,可以用G1替换CMS

  • 存活对象占堆栈50%以上
  • 对象分配率或晋升老年代率变化比较大
  • GC暂停时间长或压缩停顿时间长(超过0.5s)

CMS的分代思想是基于这样一个经验:98%的对象都是朝生夕死,所以大部分对象在新生代进行minor GC时被回收掉,只有小部分对象晋升到老年代;老年代缓慢增长且老年代中大部分对象都是垃圾,一次major GC可以释放大部分老年代空间。如果存活对象较多,那么major GC比较频繁,且空间释放率也不高;CMS新生代和老年代是在JVM启动时指定,运行过程中不能动态调整的,如果对象分配率或老年代晋升率变化比较大,则CMS很难去适应变化。

G1可根据历史每一次垃圾收集经验值,估算本次回收的region数,从而控制GC停顿时间。在全局标记时获取到每个region的垃圾占用情况,且全局标记是并发进行,所以堆栈的大小及存活对象的多少不会对停顿时间造成影响。

G1适合内存超过6GB,且延时低于0.5s的应用场景

G1垃圾收集过程

这里写图片描述

整个堆物理上被划分为很多大小相同的region,每个region大小在1MB~32MB(可以通过参数配置),总共region数不超过2048个。

逻辑分代

整个堆逻辑上被划分为eden区、survivor区、old区,每个区都是由一组region构成(region可以不连续),eden区和survior区组成新生代,old区组成老年代。

remembered set(Rset)

分代收集出现的一个问题是:垃圾回收时只是收集部分内存,怎么知道回收内存中哪些对象是被跨带引用?很容易想到用一个数据结构把这种跨带访问引用(通常是老年代引用新生代对象)给记下来,Rset就是做这个事情的。

CMS中Rset记录的是新生代和老年代之间的跨带引用;G1中每个region都有一个单独的Rset,记录的是所有指向该region的引用;G1通过对Reference写操作产生的Write Barrier中断,把引用信息更新到它所指向的region对应的Rset中。 在扫描region进行标记时,就可以并发扫描每个region的Rset,而不用扫描整个堆。

Yong GC

对象首先被分配到新生代,当新生代被占满时发生Yong GC。与CMS类似,eden区和survior区的存活对象会被拷贝到新的region,survior区中超过指定age的对象晋升到老年代;同样Yong GC是需要STW(stop-the-world)。

Mixed GC

新生代GC和老年代同时发生GC时,称为Mixed GC。G1在对全堆存活对象进行标记(Marking cycle)后会发生Mixed GC;当整个堆使用比例超过InitiatingHeapOccupancyPercent指定值时,会触发全堆标记,进而触发Mixed GC。-XX:InitiatingHeapOccupancyPercent=\ 默认为45。全堆标记包含以下阶段:

初始标记(Initial marking phase)

标记出root region,此阶段发生在Yong GC的最后,且包含在Yong GC中。由此可以看出Mixed GC发生过程:Yong GC => Marking Cycle => Mixed GC

Root region扫描(Root region scanning phase)

扫描survior区中由初始标记出来的root region,找出指向old区的对象引用,并标记引用对象;该阶段与应用并发进行,必须在下一个Yong GC发生之前完成。

并发标记(Concurrent remark phase)

扫描整个堆,找到所有存活对象;该阶段与应用并发进行,可以被Yong GC中断。

重新标记(Remark phase)

这个阶段会修正在并发标记阶段因用户线程运行导致出现偏差的部分标记记录。在mark cycle开始时,G1会记录当前堆中存活对象的快照(Snapshot-at-the-beginning/SATB);重新标记阶段会遍历所有SATB缓存,搜索出已经不可达的对象,并处理这些引用。该阶段需要暂停应用(STW)。

清理(Cleanup phase)

清理阶段做的事情,首先是统计记录所有空region和下次Mixed GC时的候选region,并且清理Rset,这个过程是STW的;然后重置空region并放入空闲队列,这个过程是并发的。

参数调优

G1重要参数列表:

参数及默认值 解释及取值参考 -XX:G1HeapRegionSize=n 每个region大小,取值在1MB~32MB之间且2的次方,
region个数不超过2048个,调整参数使得region个数尽可能多 -XX:MaxGCPauseMillis=200 最大GC停顿时间,默认是200ms -XX:G1NewSizePercent=5 新生代内存暂用下限,默认为heap的5% -XX:G1MaxNewSizePercent=60 新生代内存占用上限,默认为heap的60% -XX:ParallelGCThreads=n STW时收集线程的并发数,CPU个数小于等于8时,设置n为CPU的个数;
当CPU个数大于8时,设置n为CPU个数的5/8;
SPARC系统中,设置n为CPU个数的5/16 -XX:ConcGCThreads=n 并发标记线程数,设置n为并发搜集线程数(ParallelGCThreads)的1/4 -XX:InitiatingHeapOccupancyPercent=45 触发marking cycle的heap使用阈值,默认为heap的45% -XX:G1MixedGCLiveThresholdPercent=85 指定old region会被mixed GC选中回收时的空间使用阈值,默认为85%,
当old region空间使用超过85%时,那么在mixed GC时,该region会被回收掉 -XX:G1HeapWastePercent=5 当可回收内存小于指定值时,不会触发Mixed GC, 默认为5% -XX:G1MixedGCCountTarget=8 指定在marking cycle之后,用于收集老年代的mixed GC个数,
启动多个mixed GC可以缩短老年代的收集时间 -XX:G1OldCSetRegionThresholdPercent=10 指定一个mixed GC时回收的old region的最大个数,默认为heap的10% -XX:G1ReservePercent=10 设置保留内存大小,用于避免对象拷贝时新的region空间不足的情况,默认预留heap的10%,
要根据整个heap的大小调整改值

调优遵循的原则

  • 新生代大小:不要显式地通过-Xmn,-XX:NewRatio设置新生代大小
  • GC暂停时间:平衡GC暂停时间和吞吐量,短暂停要以牺牲吞吐量为代价,G1的目标是90%的应用时间,10%的暂停时间。
  • 调整Mixed GC参数:
    调整标记触发阈值:-XX:InitiatingHeapOccupancyPercent
    调整mixed GC触发条件:-XX:G1MixedGCLiveThresholdPercent 和 -XX:G1HeapWastePercent
    调整old region回收限制:-XX:G1MixedGCCountTarget 和 -XX:G1OldCSetRegionThresholdPercent

大对象及大对象分配

大小超过region大小一般的对象成为大对象,大对象直接被分配在老年代中的humongous regions中,如上图G1 Heap划分图 H标识的区域。humongous regions是一组连续的region,StartsHumongous标识开头region,ContinuesHumongous标识后续region。

这里写图片描述

  • humongous regions由开头的startshumongous region后跟连续的一个或多个continueshumongous region组成
  • 最后一个region会产生内存碎片

大对象在marking cycle的cleanup阶段和Full GC时回收;为了减少大对象拷贝的开销,在回收拷贝存活对象阶段不对大对象进行拷贝,所以碎片会一直存在到发生Full GC; Full GC发生时会整理压缩大对象的内存空间。
如果因为大对象碎片问题导致不断出现并发标记,可以通过-XX:G1HeapRegionSize调整region大小,将大对象变成正常对象。

总结

本文首先介绍了G1垃圾收集器的特点、定位及使用场景,然后介绍了G1的基本实现原理及GC过程,最后介绍了G1常用调优参数及调优注意事项和大对象分配时出现的碎片问题。

参考

http://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/
http://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/generations.html
http://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc.html
http://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html
http://blog.csdn.net/iter_zc/article/details/41825395

原创粉丝点击