G1垃圾收集器

  • 同时注重吞吐量和低延迟,默认的暂停目标是200ms
  • 超大堆内存,会将堆划分为多个大小相等的Region
    • G1HeapRegionSize=size ,调整每个Region的大小
  • 整体上是标记 + 整理算法,两个Region之间是复制算法

-XX:+UseG1GC JDK9之后默认启用G1收集,JDK9之前若要使用G1收集器需要手动开启

 Young Collection

每个Region都可以独立的作为Eden,幸存者区,老年代。

开始的时候,每个格子都是白的,没有创建任何对象,只有几个Eden的区域,存放类加载的时候创建的一些对象。当这些Eden区逐渐被沾满,会触发新生代的回收,会引发短暂的STW

 将幸存下来的对象复制到幸存者区,不断有对象创建,Eden区满触发youngGC,当有对象的寿命大于阈值,晋升老年代,不够年龄的幸存者区中的对象,拷贝到另一个幸存者区中

 Young Collection + CM

  • 在Young GC 时会进行GC Root 的初始标记
  • 老年代占用的堆空间比例达到阈值时,进行并发标记(不会STW),由下面的JVM参数决定
  • 从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以 后,还要重新处理SATB记录下的在并发时有引用变动的对象。 

STAB原始快照

当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描 一次。这也可以简化理解为,无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来进行搜索。

 

当一个白色对象已经被切断了和这个灰色对象的联系,但同时又有黑色对象指向他 ,但是程序并不知道又有一个黑色对象指向了他,程序不会重新扫描,原始快照就会将这个被删除的引用记录下来,等并发扫描结束后,再去扫描这些被删除的引用。

无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来进行搜索。

Mixed Collection

会对E、S、O进行全面垃圾手机

  • 对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。
  • 筛选回收:负责更新Region的统计数据,对各个Region的回 收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region 构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧 Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行 完成的。

 Eden区会被复制到幸存者区,年龄不够的复制到另外一个幸存者区,年龄达到阈值的到老年代中,对于老年代,会采用标记复制的算法,对部分老年代进行回收,但并非所有的老年代Region都进行垃圾回收,G1会根据用户的最大暂停时间,有选择的对老年代进行回收,G1就会中老年代中选择出回收价值高的的,挑一部分进行回收,达到我们减少暂停时间的目标。

G1垃圾收集的Full GC

  • 新生代内存不足触发Minor GC
  • 当老年代占比堆内存大于某个值(默认值45%),就会触发混合收集(并发标记+最终标记+筛选回收)
  • 如果回收速度比新产生的垃圾的速度快,不叫Full GC
  • 但当垃圾产生的速度跟不上垃圾回收的速度了,会发生并发收集失败,退化成串行的收集SerialGC,这叫Full GC(CMS也同理)

G1_新生代_跨代引用

  • 新生代回收的跨带引用(老年代引用新生代)问题

卡表

        记忆集是一种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构。如果我们不考虑效率和成本的话,最简单的实现可以用非收集区域中所有含跨代引用的对象数组来实现这个数据结构

        这种记录全部含跨代引用对象的实现方案,无论是空间占用还是维护成本都相当高昂。而在垃圾 收集的场景中,收集器只需要通过记忆集判断出某一块非收集区域是否存在有指向了收集区域的指针 就可以了,并不需要了解这些跨代指针的全部细节。

        每个记录精确到一块内存区域,该区域内有对象含有跨代指针。

        将一块老年代分为一个个512K的小块,当这一块中有对象含有跨带引用的话,就将这个地方变为“脏卡 ,查找有跨带引用的对象时候,仅仅扫描带有藏卡标记的位置即可,加快扫描的进度。

G1的重新标记阶段

 在A被扫描完成,被染色为黑色之后,有用户又在A中新添加了对C对象的引用,这使得原本应该被删除的C对象,变得不应该被删除,但是收集器已经扫描过A并且染色为黑,表明不会再去扫描A的引用,为了避免C被删除的情况发生。

当我们的对象引用发生改变时候,JVM会为他加入一个写屏障(类似AOP),只要对象引用发生改变,写屏障代码就会执行,比如把C的引用给一个A的属性,C的引用发生了变化,写屏障指令会把C加入到一个队列当中,并将C染色为灰。

当重新标记的过程中会STW, 重新标记的过程会对队列中的对象进行重新的扫描,使得C不会被当做垃圾收集掉。

G1的字符串去重

  • 将所有新分配的字符串放入一个队列
  • 当新生代回收时,G1并发检查是否有字符串重复
  • 如果它们的值一样,让他们引用同一个char[]

什么是重复字符串呢?

String string1 = newString("Hello King");
String string2 = newString("Hello King");

两个字符串对象string1和string2,它们的内容是一样的,都是Hello King,但是string1和string2是两个不同的对象。

string1.equals(String2)=true,但是(string1==string2) =false,所以string1和string2就是所谓的重复对象。

开启参数:-XX:+UseG1GC-XX:+UseStringDeduplication // 默认开启

 G1的并发标记类卸载

所有的对象都经过并发标记之后,就能知道哪些类不可以再被使用,当一个类加载器的所有类都不再使用,则卸载它加载的所有类,主要针对于自定义类加载器

-XX:+ClassUnloadingWithConcurrentMark,默认开启的

G1关于巨型对象的回收

  • 一个对象大于Region的一半时,称之为巨型对象,占据几个连续的region
  • G1不会对巨型对象进行拷贝
  • 回收时会优先考虑

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值