早期垃圾回收器+G1垃圾回收器总结

1.Parallel Scavenge+Parallel Old

Parallel Scavenge负责年轻代垃圾回收,采用复制算法,多线程并行回收。

Parallel Old负责老年代垃圾回收,采用标记-整理算法,多线程并发收集,暂停时间会比较长。

2.ParNew+CMS

ParNew负责年轻代垃圾回收,采用复制算法,多线程并行回收。

CMS负责老年代垃圾回收,采用标记-清除算法,停顿时间较短。但是会存在内存碎片问题
、退化问题、CPU资源敏感问题和浮动垃圾问题。

CMS垃圾回收过程:

总共分为四步:

1.初始标记:stop the world,标记和GC root直接关联的对象。

2.并发标记:用户线程和标记线程同时进行,标记所有对象。

3.重新标记:stop the world,标记上一个并发步骤中产生的新垃圾。

4.并发清除:用户线程和垃圾回收线程同时进行,清除已经标记的垃圾。

CMS产生的三个问题:

1.内存碎片:因为CMS采用的是标记-清除算法,所以会产生内存碎片。

2.浮动垃圾:因为在第4步并发清除阶段也会有新的垃圾出现,这类垃圾就叫浮动垃圾,需要等到下一次的垃圾回收过程中才能被清除。

3.容易退化成Serial Old垃圾回收器:当创建一个新的大的对象需要被放到老年代,但是老年代内存不够的时候,会退化成Serial Old垃圾回收器重新来对老年代的垃圾收集。

4.CPU资源敏感:CMS 中并发阶段运行时的默认线程数=(CPU的数量 + 3) / 4,所以CPU数量少会导致程序变慢。

G1垃圾回收器:

特点:将整个堆划分成多个大小相等的区域,叫Region。每个Region可以是Eden 、Survivor 、或者Old 区。Region size必须是2的指数幂,取值范围从1M到32M。

垃圾回收方式:

1.年轻代回收:回收Eden 区和Survivor 区中不用的对象,采用复制算法。可以设置每次垃圾回收时的最大暂停时间毫秒数。

注意:

1.新创建的对象会存放在Eden 区。当G1判断年轻代占总堆的百分之六十以上时,无法分配对象时需要回收时会执行Young GC 。
2.标记出Eden 和Survivor 区域中的存活对象,
3.根据配置的最大暂停时间选择某些区域将存活对象复制到一个新的Survivor 区中(年龄+1 1),清空这些区域。

当对象年龄达到15,将被放到老年代。

如果对象超出Region的一半,那么会被直接放到老年代中,这种老年代叫Humongous区,这种老年代可以连续占用多个Region。

2.混合回收:

注意:

当总堆占有率达到阈值时默认45%时会触发混合回收MixedGC 。回收所有年轻代和部分老年代的对象以及大对象区,采用复制算法来完成,如果发现没有空的Region来存放,就会FULL GC,会单线程执行标记-整理算法。

G1解决跨代引用的方法:

加入老年代引用了Eden区的对象,且这个Eden区的对象没有被其他Eden区的对象引用,就出现了跨代引用的问题。因为Young GC只会扫描年轻代里的所有对象,因此这个对象会被当做垃圾清理掉,导致老年代出现空指针异常。

解决方案:使用卡表。

卡表本质上就是一个字节数组,每一个Region都有一个卡表,卡表数组的每一个下标代表对应一个512字节的区域。如果该区域存在跨代引用,卡表对应位置的数值设为0(dirty card),并把它加入到记忆集中。当Young GC时,会把记忆集对应区域的对象加入到GC root对象中进行扫描。

当老年代引用年轻代对象时会使用卡表,那么G1如何实现这个功能?

使用写屏障:在建立引用关系时,利用写屏障将跨代应用记录到卡表中。

记忆集记录跨代引用整体流程:

1.通过写屏障指令将跨代引用记录到卡表。

2.将记录写到脏卡队列中。

3. 通过Refinement线程消费脏卡队列,进行记忆集的更新。

G1垃圾回收器年轻代回收的完整流程:

1.Root扫描,获取GC Root。

2.更新完成最终记忆集。

3.标记存活对象,将记忆集内的对象也加入到GC Root中。

4.设置最大存活时间,选择收集区域。

5.复制算法清除对象。存活对象年龄加1,如果到达15,晋升老年代。

6.处理软、弱、虚、终结器引用。将已经回收的对象加入到对应的引用队列。

G1垃圾回收器混合回收的完整流程:

总共分为四步:

第一步.初始标记:stop the world,采用三色标记算法标记GC Root直达的对象。

三色标记算法中黑色代表当前对象和子对象已经被扫描、灰色带表当前对象已经被扫描、白色代表当前对象还没有被扫描。

第二步.并发标记:用户线程和标记线程同时进行,沿着第一步的对象继续标记所有对象。

存在问题:并发标记的过程中,用户线程修改了引用关系导致错标的情况。

解决方案:

SATB技术(初始快照技术)过程:

1.标记开始先创建一个快照,记录所有对象,标记过程中新生成的对象直接标记为黑色。

2.采用写屏障技术,在用户改变引用关系的语句之前进行判断,引用的对象是否在初始快照当中?如果在的话就将这个对象放到这个线程的SATB待处理队列中。最终将多个线程的SATB待处理队列合并成一个大的SATB处理队列。

第三步.最终标记:stop the world,将SATB队列中的对象默认存活,同时处理它们引用的对象。

这一步也存在缺点:就是会产生浮动垃圾,将这一轮已经是垃圾的对象标记成了存活,需要等到下一次垃圾清理再清理掉。

第四步.清除:stop the world,如果区域内没有任何存活对象就直接清理掉。

第五步.转移:最终根据最终标记的结果,计算出每一个区域的垃圾占用内存的大小,根据设置的停顿时间选择转移效率最高的几个区域,采用复制算法转移。如果Region不够了,则进行单线程的FULL GC,使用标记-整理算法。

其中G1对老年代的清理会选择存活度最低的区域来进行回收。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值