JVM -- JVM中垃圾回收器

参考:《深入理解Java虚拟机》,徐无忌老师的教学视频

参考博客:https://www.jianshu.com/p/9e70097807ba

上图为HotSpot虚拟机中的垃圾收集器

新生代的垃圾收集器:

  • Serial
  • ParNew
  • Parllel Scavenge

 

老年代的垃圾收集器:

  • CMS
  • Serial Old
  • Parallel Old

 

上图中如果收集器之间存在连线,说明可以搭配使用,但不是一成不变的,由于维护和测试兼容性测试的成本,在JDK8中将Serial+CMS、ParNew + Serial Old组合声明为废弃,并在JDK9中完全取消了这些组合的支持。

 

新生代垃圾回收器整理

Serial收集器

1、Serail收集器是一个单线程收集器,也就是说当该收集器在进行垃圾收集的时候会引发“Stop The Word”,即执行应用线程的时候,不会执行GC,执行GC的时候,不会执行应用线程

2、Serial收集器是最基础的、历史最悠久的收集器,在JDK3之前,是HotSpot虚拟机新生代唯一的选择

3、Serial采用的是标记-复制算法

上图是Serial/Serial old收集器示意图

 

ParNew收集器

1、ParNew收集器实质上是Serial收集器的多线程版本,许多代码都是和Serial收集器公用的。除了支持多线程并行收集之外,并没有太多的创新之处,当ParNew收集器工作的时候同样会造成"Stop The Word"

2、在JDK7之前,ParNew收集器是新生代首选的垃圾收集器,原因:处理Serial收集器,目前只有ParNew收集器能和CMS收集器(老年代收集器)配合使用

3、从JDK9开始,官方推出了G1收集器,目的使用希望使用G1收集器替代ParNew+CMS收集器的组合

4、采用的是标记-复制算法

上图是ParNew/Serial old收集器示意图

 

理解“并行”和“并发”收集器的概念:

并行(Parallel):垃圾回收线程在运行的时候,用户线程处于等待状态。即当GC时,造成“Stop the word”

并发(Concurrent):同一时间垃圾收集器线程和用户线程都在运行,由于用户线程并未冻结,所以程序仍然能够响应服务请求,但由于垃圾收集器线程占用了一部分系统资源,应用程序的吞吐量会造成一定的影响

 

Parallel Scavenge收集器

1、该收集器同样基于标记-复制算法,是一款并行收集的多线程收集器,同样运行的时候会造成“Stope the word”.

2、Parallel Scavenge收集器和其他收集器的关注点不同,该款收集器关注的时吞吐量,即用户代码运行的时间与处理器总消耗时间的比值

3、它提供了一个适应的调节策略

  • 只需要设置好参数,给虚拟机设立一个优化目标,那具体的调节工作就由虚拟机本身完成
  • MaxGCPauseMillis参数:关注最大停顿时间
  • GCTimeRatio参数:关注吞吐量
  • 自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别

 

 

老年代垃圾收集器

 Serial  Old收集器

1、 Serial  Old收集器时Serial收集器的老年代版本,同样使用单线程进行垃圾收集,采用的是标记-整理算法

2、使用场景主要是供客户端模式下的HotSpot虚拟机使用

3、用途:1、在JDK5以及之前的版本与Parallel Scavenge收集器搭配使用。2、作为CMS收集器发生失败时的后备预案,在并发收集时发生Concurrent Mode Failure时使用

 

Parallel Old收集器

1、这个回收器是Parallel scavenge的老年代版本,支持多线程并行收集,采用的是标记-整理的算法,该收集器是在JDK6的时候才开始提供

2、经常和Parallel scavenge一起使用,在对内存比较敏感和对吞吐量比较高的场合下优先使用

上图是Parallel scavenge/Parallel Old收集器运行示意图

 

CMS收集器

1、CMS(Concurrent Mark Sweep)收集器是HotSpot在JDK推出的第一款真正意义上的并发(Concurrent)收集器。第一次实现了让垃圾线程和用户线程(基本上)同时工作

2、它是一种获取最短回收停顿时间为目标的收集器

3、CMS收集器采用的是标记-清除算法

 

CMS收集过程分为四步:

  1. 初始标记(CMS initial mark):该步骤仅仅标记一下“GC Roots”能直接关联到的对象,需要暂停用户线程,速度很快,耗时短
  2. 并发标记(CMS concurrent mark):就是从“GC Roots”直接关联对象开始遍历整个对象图的过程,这个过程耗时较长,但不需要停顿用户线程
  3. 重新标记(CMS remark):对并发标记期间新增的引用关系再次标记,需要暂停用户线程(耗时短)
  4. 并发清除(CMS concurrent sweep):清理删除掉标记阶段已经死亡的对象,不需要暂停用户对象

 

CMS收集器的缺陷:

1、CMS收集器对处理器资源非常敏感,会跟用户线程竞争资源,从而导致应用程序运行变慢,降低总吞吐量

2、CMS收集器在垃圾收集的过程中,用户线程仍在持续运行,所以在并发清除时必须预留一部分空间留给应用程序进行运作。因此,CMS收集器不能像其他收集器那样等待老年代几乎完全被填满再进行收集

注:JDK5中,CMS默认的启动阈值为68%,JDK6,该值默认提升到了92%,可以通过设置该“-XX:+UseCMSCompactAtFullCollection”参数的值来改变CMS的启动阈值。如果这个设置的太高,在并发清理的时候,用户线程并发执行可能没有足够的空间给对象进行内存分配,就会出现一次Concurrent Model Failure,

那么老年代收集器就会自动转换使用serialOld收集器进行回收,从而导致用户线程的停顿时间变长,所以这个值设置的合理很重要。

3、由于CMS收集器无法处理"浮动垃圾"(Floating Garbage),有可能出现“Concurrent Mode Failure”失败。这个时候会使用备用的垃圾收集器Serial Old 垃圾回收器进行一次完成“Stop The Word”的Full GC的产生

注:“浮动垃圾”:在CMS并发标记和并发清理阶段,用户线程仍在继续运行,就会产生新的垃圾对象,但这一部分垃圾对象时出现在标记过程之后,CMS无法在当次垃圾收集中清除掉,这部分垃圾就是“浮动垃圾”

4、CMS收集器采用的是“标记-清除”算法,会产生大量的空间碎片

注:为了解决该问题,CMS收集器提供−XX:+UseCMSCompactAlFullCollection开关,默认是开启的,用于在CMS进行Full GC时对内存碎片进行合并整理工作。JDK9 开始废除这个变量

 

Mixed GC收集器

G1收集器:

1、Garbage First(简称G1)收集器是垃圾收集器技术史上的里程碑式的成果,它开创了收集器局部收集的设计思想和基于Region的内存布局形式。从G1开始,最先进的垃圾收集器设计导向不约而同的变为追求能够应付应用内存分配速率(Allocation Rate),而不追求一次把整个Java堆全部清理干净。这样,应用在分配,同时收集器在收集,只要收集速度能够大于分配速度,那一切运作都会变的相当完美。

2、G1是一款面向服务器端应用的垃圾收集器

3、从整体上看采用的是“标记-整理”,从局部(两个Region之间)上来看又是基于“标记-复制”算法,(看来大神也有没弄明白的问题),总之,G1不会产生空间碎片

上图为G1收集器Region分区示意图

G1将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔阂了,它们都是一部分可以不连续Region的集合。

G1收集器采用的收集方式为Mixed GC模式(混合模式)

Humongous区域是用来专门存储大对象的

上图为G1收集器运行示意图

G1的运作过程大致可划分为四个步骤:

  1. 初始标记:仅仅只是标记一下GC Roots能够直接关联到的对象,并修改TAMS指针的值,让下一个阶段用户并发运行时,能正确的在可用的Region中分配新的对象
  2. 并发标记:从GC Roots开始对堆中的对象进行可达性分析,递归扫描整个堆中的对象图,找出要回收的对象,这个阶段耗时较长,但可与用户程序并发执行,当对象扫描完成之后,还要重新处理SATB记录下的在并发时有引用变动的对象。
  3. 最终标记:对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录
  4. 筛选标记:负责更新Regiond的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间指定回收计划,可以自由选择任意多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,在清理掉整个旧Region的全部空间。这里的操作设计到存活对象的移动,是必须暂停用户线程,由多条收集器线程并行完成

注:G1垃圾收集器之SATB(原始快照 Snapshot At The Beginning) -- 对象漏标

垃圾回收的并发标记阶段,gc线程和应用线程是并发执行的,所以一个对象被标记之后,应用线程可能篡改对象的引用关系,从而造成对象的漏标、误标,其实误标没什么关系,顶多造成浮动垃圾,在下次gc还是可以回收的,但是漏标的后果是致命的,把本应该存活的对象给回收了,从而影响的程序的正确性。

来自:https://www.jianshu.com/p/9e70097807ba

Safe Point就是JVM执行到某一个位置能够安全可控的回收对象

 

查看默认垃圾回收器的指令:java -XX:+PrintCommandLineFlags -version

JDK8中,显示为UseParallelGC : 即 Parallel Scavenge + Serial Old

从JDK9开始,默认使用G1

 

JDK11又新加入了ZGC(目前处于实验阶段)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值