对JAVA垃圾回收器的一些理解

垃圾回收器总结

不同垃圾回收器适合回收的内存大小:
1、Serial 几十兆
2、Parallel 上百兆至几个G
3、CMS 几十G
4、G1 上百G
5、ZGC T级别 (JDK13)

按运行方式分:

  • 并行回收器:Parallel Scavenge、Parallel old
  • 并发回收器:CMS、G1

按照作用的收集区域分:
年轻代:Parallel Scavenge
老年代:Parallel old、CMS
G1、ZGC都可以回收

Parallel(并行、java8默认垃圾回收器)

Parallel Scavenge:复制算法、并行回收,用于新生代。
Parallel old:标记-整理算法、并行回收、用于老年代

G1 vs CMS

G1整体比CMS优秀一些,比如:

回收区域:
CMS只能用于老年代回收,G1可用于新生代和老年代的回收

GC情况
CMS:
采用标记-清除算法,会产生内存碎片
G1:
采用标记-清除-整理算法,没有内存碎片

G1支持软实时回收
实时垃圾回收要求必须在规定时间内完成垃圾回收
而“软实时”则可以由用户指定垃圾回收时间的限时,G1会努力在这个时限内完成垃圾回收,比CMS更加灵活。

CMS(速度最快)

Concurrent-Mark-Sweep:并发标记清除算法
是java的第一款并发收集器,最大的特点就是回收速度快,因为采用的是标记清除算法,相较标记清除整理算法少了整理的时间,但是会有内存碎片。

四个回收阶段

CMS整个工作过程分为4个主要阶段:
初始标记阶段、并发标记阶段、重新标记阶段和并发清除阶段
在这里插入图片描述

初始标记阶段
从GCRoot寻找直达的对象

并发标记阶段
通过直达对象,标记所有的可达对象

重新标记阶段
由于并发标记阶段是gc线程和用户线程并发执行,这个过程中,用户线程可能修改对象的引用,
所以需要在重新标记阶段,修正并发标记阶段造成的错误。

并发清除阶段
采用标记-清除算法清理死亡的对象,释放内存空间

G1(jdk9默认收集器、综合性能最优)

G1是一个
分代的(同时分别采用不同的算法回收新生代和老年代)
增量的(不是一次性回收而是多次,一次回收一点)
分区的(核心特点,下面介绍)
采用标记-整理算法的垃圾回收器。

G1最大的特点就是分区
G1把堆内存分割为很多物理上不连续的的区域(Region),使用不同的Region来分别表示Eden、幸存者0区,幸存者1区,老年代

G1适合收集大内存
因为G1是增量式清理,保证每次GC停顿时间不会过长,所以越是大内存,相对不是增量式的收集器,G1停顿的时间越少,优势就越明显。

G1内存区域图
在这里插入图片描述
Humongous内存区域
Humongous内存区域是G1垃圾收集器新增的内存区域,主要用于存储大对象,如果超过1.5个region,就放到Humongous。

G1垃圾回收器的回收过程

G1GC的垃圾回收过程主要包括如下三个环节:

  • 年轻代GC(Young GC)
  • 老年代并发标记(Concurrent Marking)
  • 混合回收(Mixed GC)

在这里插入图片描述
1、当年轻代的Eden区用尽时,开始年轻代回收过程
G1的年轻代收集阶段是一个并行独占式收集器。在年轻代回收期,G1GC暂停所有应用程序线程,启动多线程执行年轻代回收。然后从年轻代区间移动存活对象到Survivor区间或者老年区间,也有可能是两个区间都会涉及。

2 、当堆内存使用达到一定值(默认45%)时,开始老年代并发标记过程。

3 、标记完成马上开始混合回收过程。
对于一个混合回收期,G1GC从老年区间移动存活对象到空闲区间,这些空闲区间也就成为了老年代的一部分。和年轻代不同,老年代的G1回收器和其他GC不同,G1的老年代回收器不需要整个老年代被回收,一次只需要扫描/回收一小部分老年代的Region就可以了。同时,这个老年代Region是和年轻代一起被回收的。

年轻代GC

JVM启动时,G1先准备好Eden区,程序在运行过程中不断创建对象到Eden区,当Eden空间耗尽时,G1会启动YGC。

YGC时,首先STW停止应用程序的执行,G1创建回收集(Collection Set)
回收集是指需要被回收的内存分段的集合,年轻代回收过程的回收集包含Eden区和Survivor区的所有的内存分段

下图就是进行YGC,存活的对象进行移动,有的移入Survivor,有的移入old
在这里插入图片描述
然后开始如下回收过程

  • 第一阶段,扫描根
    根引用RSet记录的外部引用作为扫描存活对象的入口。

  • 第二阶段,更新RSet
    更新RSet。此阶段完成后,RSet可以准确的反映老年代对所在的内存分段中对象的引用。

  • 第三阶段,处理RSet
    识别被老年代对象指向的Eden中的对象,这些被指向的Eden中的对象被认为是存活的对象。

  • 第四阶段,复制对象。
    遍历对象树,Eden区内存段中存活的对象会被复制到Survivor区中空的内存分段,Survivor区内存段中存活的对象如果年龄未达阈值,年龄会+1,达到阀值会被复制到old区中空的内存分段。如果Survivor空间不够,Eden空间的部分数据会直接晋升到老年代空间。

  • 第五阶段,清理死亡对象
    清理死亡对象之后Eden空间的数据为空,GC停止工作,而目标内存中的对象都是连续存储的,没有碎片,所以复制过程可以达到内存整理的效果,减少碎片。

老年代并发标记过程

  • 初始标记阶段
    标记从根节点直接可达的对象,STW,触发一次年轻代GC。

  • 根区域扫描(Root Region Scanning)
    G1 Gc扫描survivor区直接可达的老年代区域对象,并标记被引用的对象。这一过程必须在youngGC之前完成。

  • 并发标记(Concurrent Marking)
    和应用程序并发执行,在整个堆中进行并发标记,此过程可能被youngGC中断。在并发标记阶段,若发现区域对象中的所有对象都是垃圾,那这个区域会被立即回收。同时,并发标记过程中,会计算每个区域中存活对象的比例。

  • 再次标记(Remark)
    由于应用程序持续进行,需要修正上一次的标记结果。
    STW

  • 独占清理(cleanup,STW)
    计算各个区域的存活对象和GC回收比例,并进行排序
    识别可以混合回收的区域。为下阶段做铺垫。
    STW
    这个阶段并不会做垃圾收集

  • 并发清理阶段
    识别并清理完全空闲的区域。

G1回收过程 - 混合回收

当越来越多的对象晋升到老年代old region时,为了避免堆内存被耗尽,虚拟机会触发一个混合的垃圾收集器,即Mixed GC,该算法除了回收整个Young Region,还会回收一部分old Region。混合回收的算法和年轻代回收的算法完全一样,只是回收集多了老年代的内存分段。

老年代中的内存分段默认分8次回收,G1会优先回收垃圾多的内存分段。垃圾占内存分段比例越高的,越会被先回收。

Full GC(非必须)

G1的初衷就是要避免FullGC的出现,但是没法完全避免

导致FullGC的原因可能有两个:

  • 回收阶段的时候没有足够的to-space来存放晋升的对象;
  • 并发处理过程完成之前空间耗尽。

革命性的ZGC

ZGC的目标是:

  • 停顿时间不会超过10ms
  • 停顿时间不会随着堆的增大而增大(不管多大的堆都能保持在10ms以下)
  • 可支持几百M,甚至几T的堆大小(最大支持4T)

ZGC特性

  • 低延迟

  • Concurrent(并发执行)

  • Region-based(内存基于region,类似G1)
    ZGC中没有新生代和老年代的概念,只有一块一块的内存区域page,这和G1的region有点像,但和G1不一样的是,region的大小更加灵活和动态。zgc的region不会像G1那样在一开始就被划分为固定大小的region。

  • Compacting(压缩)

  • colored pointers(着色指针)

  • load barriers(读屏障)
    因为在标记和移动过程中,GC线程和应用线程是并发执行的,所以存在这种情况:对象A内部的引用所指的对象B在标记或者移动状态,为了保证应用线程拿到的B对象是对的,那么在读取B的指针时会经过一个 “load barriers” 读屏障,这个屏障可以保证在执行GC时,数据读取的正确性。

ZGC未来将是服务端、大内存、低延迟应用的首选垃圾收集器。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值