JVM-GC垃圾回收器(二)

系列文章目录

本文是JVM中第二章,主要讲GC垃圾回收器,分析特点。 阅读之前建议,先去参考第一章

GC算法及其原理



前言

我们已经学习了GC的算法,但是这么多算法,并不可能全部用得到。举个栗子:相当于我们有了食材,但是今天吃什么,并不确定,要做什么菜,需要我们自己搭配。 JVM已经帮我们实现了基于不同算法的多种GC垃圾回收器,我们只需要根据项目应用环境和需求做出选择即可。

提示:以下是本篇文章正文内容,下面案例可供参考

一、Serial收集器

简介

Serial收集器又名串行回收器,顾名思义,GC线程线性执行垃圾回收操作。
  • 会利用单核cpu进行单线程执行GC操作
  • 会产生STW,vm无感知的暂停掉应用程序,直到GC操作完成

Serial/Serial Old收集器
在这里插入图片描述

缺点

由于STW,每过一段时间就会暂停应用程序,进行GC操作,应用用户使用。

优点

  • 高效,单只是与其他收集器的单线程版相比
  • 对于单个cpu环境,因为没有线程交互的消耗,所以在单核或单线程情况下,会获得较高执行效率。

应用

-XX:+UseSerialGC 串行收集器
在VM管理内存不大的情况下(收集几十M~一两百M的新生代), 停顿时间完全可以控制在几十毫秒~一百多毫秒内.

二、ParNew收集器

简介

ParNew收集器是Serial收集器多线程版本(是GC线程的多线程,并行)。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/e8a9b78f168a471a85aefa2f69a063c1.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5Lic6aOO5oG85oiRLi4u,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

缺点

在单CPU的环境中绝对不会有比Serial收集器更好的效果,甚至存在线程交互的开销。

优点

  • 除了Serial收集器外,只有ParNew收集器能与CMS收集器配合工作。
  • CMS(Concurrent Mark Sweep)第一次实现让垃圾收集线程与用户线程(基本上)同时工作。

应用

运行在Server模式下的VM首选新生代收集器。
  • 使用-XX:+UseConcMarkSweepGC选项后默认新生代收集器为ParNew收集器;
  • 使用-XX:+UseParNewGC选项强制指定使用ParNew收集器;
  • 使用-XX:ParallelGCThreads参数限制垃圾收集的线程数;

三、Parallel Scavenge收集器

简介

  • Parallel Scavenge收集器是一个新生代收集器,使用复制算法的收集器,并行的多线程收集器。更关注吞吐量。
  • CPU用于运行用户代码的时间与cpu总消耗时间的比值(用户代码运行时间+GC运行时间)

公式如下:

$吞吐量= \frac {应用代码运行时间} {应用代码运行时间 + GC执行时间}

应用

主要适合后台运算而不需要太多交互的任务.
在JDK1.6以前,Parallel Scavenge只能配合使用SerialOld垃圾回收器,所以老年代无法控制吞吐量,在JDK1.6以后,Parallel Old实现了老年代版本的并行垃圾回收器,使用标记-整理算法对垃圾进行回收,其他与Parallel无区别,可以搭配Parallel使用。

参数控制

用户精确控制吞吐量

  • 使用-XX:MaxGCPauseMillis参数:控制最大垃圾收集停顿时间
  • 使用-XX:GCTimeRatio参数:直接设置吞吐量大小
  • 使用-XX:+UseAdaptiveSizePolicy开关参数:GC自适应的调节策略

名词释义

  • MaxGCPauseMillis参数允许的值是一个大于0的毫秒数,收集器尽可能保证内存回收时间不超过设定值。
  • GC停顿时间缩短牺牲吞吐量和新生代空间——若将MaxGCPauseMillis该值调小带来的问题:系统把新生代调小一些,收集发生更频繁一些,吞吐量下降。
  • GCTimeRatio参数值是一个大于0且小于100的整数,即垃圾收集时间占总时间的比率,相当于吞吐量的倒数。如设置为19,则最大GC时间占1/(1+19)=5%,默认值为99.则最大允许1/(1+99)=1%的垃圾收集时间。
  • UseAdaptiveSizePolicy开关参数:VM会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大吞吐量。自适应调节策略是Parallel Scavenge收集器与ParNew收集器的重要区别。

四、Serial Old收集器

简介

Serial Old收集器是Serial收集器的老年代版本,是一个单线程收集器,使用“标记-整理”算法。

运行时示意图如Serial收集器,请自行向上翻找查看。

应用

  • 主要给Client模式下的VM使用
  • 若在Server模式下用,两大用途:1.在JDK1.5及之前的版本中与Parallel Scavenge收集器搭配使用;2.作为CMS收集器备选,并在Concurrent Mode Failure时使用。

五、Parallel Old收集器

简介

Parallel Old是Parallel Scavenge收集器的老年代版本,是一个多线程收集器,使用“标记-整理”算法。在JDK1.6开始提供。

Parallel Scavenge /Parallel Old收集器

在这里插入图片描述

应用

注重吞吐量以及CPU资源敏感的场合,优先考虑Parallel Scavenge + Parallel Old收集器。适合吞吐量优先。

六、CMS收集器

简介

CMS收集器(Concurrent Mark Sweep)是一种以获取最短回收停顿时间为目标的收集器,是基于“标记-清除”算法。

在这里插入图片描述

执行顺序:

初始标记——并发标记——重新标记——并发清除

  • 初始标记:CMS initial mark仅仅是标记一下GC Roots能直接关联的对象,速度快;需要stop the world
  • 并发标记:CMS concurrent mark是进行GC Roots Tracing的过程;
  • 重新标记:CMS remark是修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,停顿时间比初始标记长,比并发标记短;需要stop the world
  • 并发清除:CMS concurrent sweep,清除算法会在收集结束时产生大量空间碎片,有可能导致没有足够大的连续空间来分配当前对象而触发一次Full GC。

缺点

  • CMS收集器对CPU资源非常敏感
  • CMS收集器无法处理浮动垃圾,可能出现"Concurrent Mode Failure"失败(备选用Serial Old)而导致另一次Full GC的产生;
  • CMS是一款基于“标记-清除”算法的收集器,在收集结束后会产生大量空间碎片。

优点

并发收集;低停顿(并发低停顿收集器)

应用

在互联网站或者B/S系统的服务端上,重视服务的响应速度,希望系统停顿时间最短,给用户带来较好的体验。

  • 使用-XX:CMSInitiatingOccupancyFraction参数:提高触发老年代CMS垃圾回收的百分比;
  • 使用-XX:+UseCMSCompactAtFullCollection开关参数:默认开启,用于CMS收集器要进行Full GC时开启内存碎片合并整理过程,非并发的过程;
  • 使用-XX:CMSFullGCsBeforeCompaction参数:用于设置执行多少次不压缩的Full GC后,紧接着一次带压缩的(默认为0,表示每次进入Full GC时就进行碎片整理)

七、G1收集器

简介

  • G1(Garbage-First)收集器是一款面向服务端应用的垃圾收集器,为了代替JDK1.5中发布的CMS收集器。将整个Java堆划分为多个大小相等的独立区域。####(Region),保留新生代和老年代概念,但不再是物理隔离,是一部分Region的集合(不需要连续)。
  • G1的新生代收集跟ParNew类似,当新生代占用达到一定比例的时候,开始出发收集。和CMS类似,G1收集器收集老年代对象 会有短暂停顿。

执行过程:

初始标记——并发标记——最终标记——筛选回收

  • 初始标记:initial marking,标记一下GC Roots能直接关联的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,需要停顿线程,耗时短;
  • 并发标记:concurrent marking,从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时长,但可与用户程序并发执行;
  • 最终标记:final marking,修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,对象变化记录存在线程Remember Set Logs中,然后把这些数据合并到Remember Set中,该阶段停顿线程,但是可并行执行;
  • 筛选回收:live data counting and evacuation,对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来指定回收计划。
示意图如下:

在这里插入图片描述

优点

并发与并行、分代收集、空间整合、可预测的停顿

  • 并发与并行:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU缩短storp-the-world停顿时间;G1可通过并发的方式使得java程序运行;
  • 分代收集:可以独立管理整个GC堆,采用不同的方式处理新创建的对象和已经存活一段时间、熬过多次GC的旧对象以获取更好的收集效果;
  • 空间整合:整体上基于“标记-整理”算法,局部(两个Region之间)基于“复制”算法,G1运行期间不会产生内存空间碎片,收集后能提供规整的可用内存,有利于程序长时间运行,分配大对象时不会因为无法获得连续内存空间而提前触发下一次GC;
  • 可预测的停顿:相比于CMS的另一优势,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。因为可以有计划地避免在整个java堆上进行全区域的垃圾收集。G1跟踪各个Region内垃圾堆积的价值大小(回收所获得的空间大小+回收所需时间的经验值),在后台维护一个优先列表,根据允许的收集时间,回收价值最大的Region(Garbage-First的由来)。

设计思路

region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,VM都是通过Remember Set来避免全堆扫描。G1中每个Region中都有一个与之对应的Remember Set:
  1. VM发现程序对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作;
  2. 检查Reference引用的对象是否处于不同的Region之中;如果是,便通过CardTable把相关引用信息记录到被引用对象所属的Region的Remember Set之中;
  3. 当进行内存回收时,在GC根节点的枚举范围中加入Remember Set即可保证不对全堆扫描;

三、GC常用参数

常用配置参数

在这里插入图片描述


总结

JVM是从一个Java开发人员的基础,想要走向高级开发的必经之路。目前写到的都是理论知识,距离实践还有很远的话,后续有时间会补上手动实践的记录。 站在巨人的肩膀上 [引用](https://www.jianshu.com/p/5846f74405c2) [引用](https://blog.youkuaiyun.com/that_is_cool/article/details/80859321)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值