【Java虚拟机】七大垃圾回收器详解(优缺点,适用场景) - Go语言中文社区

【Java虚拟机】七大垃圾回收器详解(优缺点,适用场景)


垃圾回收器的优缺点与适用场景

阅读本文前需要了解的知识点:

  • 垃圾回收中的并行与并发
  • GC Root Tracing(可达性分析算法)

一、Serial收集器

特点: Serial收集器是最基本,发展例是最悠久的收集器。它是一个单线程收集器,即Serial收集器在工作时,必须暂停其他所有正在工作的线程,直到它的垃圾收集工作结束(即Stop The World)。Serial收集器到目前为止仍是虚拟机运行在Client模式下默认的垃圾收集器。下图为Serial/Serial Old收集器的运行过程。

优点: 简单高效。没有线程交互的开销,专注垃圾回收,可获得最高的单线程收集效率。
缺点: 收集工作进行时必须暂停其他所有正在工作的线程,会造成用户线程停顿。
适用场景: 运行在Client模式下的虚拟机(用户桌面)

二、ParNew收集器

特点:ParNew收集器相当于一个多线程版的Serial收集器,它除了能使用多线程进行垃圾回收,其余行为包括Serial收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一样。

优点:可进行多线程收集,是除了Serial收集器之外唯一能与CMS收集器配合的新生代收集器。
缺点:ParNew收集器在单线程或CPU数量较少的情况下,由于存在线程交互的开销,效率并不能百分百保证完全超越Serial收集器。
适用场景:是运行在Server模式下的虚拟机的首选新生代收集器。

三、Parallel Scavenge收集器

特点:Parallel Scavenge收集器也是一个新生代的、多线程的垃圾收集器,同样也是使用复制算法,特别之处在于它关注的重点目标是达到一个可控的吞吐量,因此又被称为“吞吐量优先收集器”。Parallel Scavenge 收集器可通过 -XX MaxPauseMills 和 -XX MaxTimeRadio两个参数来分别设置最大停顿时间和吞吐量。除此之外,Parallel Scavenge收集器还可以通过 -XX UseAdaptiveSizePolicy来开启收集器的自适应调节策略。
吞吐量:CPU用于运行用户代码的时间和CPU运行总消耗时间的比值,即吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾回收的时间),例如虚拟机总共运行了100分钟,其中一分钟用于垃圾回收,那么此时的吞吐量就是99%,高吞吐量可以高效率的利用CPU时间,使其尽快得完成运算任务,主要适合在后台运算而不需要太多交互的任务。
停顿时间:介绍 Serial 收集器的时候有提到过,回收器在进行垃圾回收都会或多或少的造成用户线程停顿,停顿的时间长度即为停顿时间。Parallel Scavenge收集器可设置停顿时间长短,但是要注意,这并不意味着会使系统的垃圾回收速度变得更快,它是以牺牲新生代的内存空间和吞吐量为代价的,由于内存空间缩小,新生代的垃圾回收就也变得更加频繁。就比如新生代原来是500M,每10秒进行一次垃圾回收,每次回收停顿100毫秒,设置MaxTimeMills 参数后,新生代变为300M,每5秒进行一次垃圾回收,每次回收停顿70毫秒,停顿时间的确是降低了,但是吞吐量也随之降低了。
自适应调节策略:不需要手动设定新生代大小(Xmm)、Eden区与Survivor区的比例(-XX SurvivorRatio)、晋升老年代对象年龄(-XX PretenureSizeThreshold)等细节参数,虚拟机会根据当前系统的运行情况收集性能监控信息,动态的调整这些参数以提供最大的吞吐量和最适合的停顿时间,自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别。

四、Serial Old收集器

特点: 和Serial收集器一样是单线程收集器,从名字就可以看出它是和Serial收集器配合使用的老年代收集器,它是基于“标记—整理”算法实现的。
优点: 高效
缺点: 单线程收集,用户停顿
适用场景: 主要给Client模式下的虚拟机使用。如果应用再Server段,则主要有两大用途:一是再JDK 1.5及其之前版本配合Parallel Scavenge收集器使用(因为Parallel Old收集器在JDK 1.6版本才出现),二是作为CMS收集器的后备预案,在Concurrent Mode Failure时使用(在CMS收集器讲解时会提到)。

五、Parallel Old收集器

特点: JDK 1.6版本才出现,多线程收集器,基于“标记整理”算法实现。未出现此收集器之前Parallel Scavenge收集器配合Serial Old收集器在服务端使用时无法充分利用服务器多CPU的处理能力,在老年代很大且硬件比较高级的情况下,Parallel Scavenge收集器配合Serial Old收集器这种组合甚至不一定有ParNew收集器加CMS收集器效率高。
适用场景: 配合Parallel Scavenge收集器使用,可用于注重吞吐量以及CPU资源敏感的场合。

六、CMS收集器

特点: CMS收集器的主要目标是获取最短的回收停顿时间,它是基于“标记-清除”算法实现的。
它的运作主要分为以下 四个步骤

  • 初始标记:需要Stop The World,仅仅标记一下GC Root能直接关联到的对象,速度很快。
  • 并发标记:进行GC Root Tracing(可达性分析算法)的过程。
  • 重新标记:需要Stop The World,修正那些在并发标记阶段由于用户程序运行而导致标记产生改变的对象的标记记录,停顿时间稍长,但远小于并发标记阶段。
  • 并发清除:清除被标记的垃圾对象。
    整个过程耗时最长的并发标记和并发清除都和用户程序一起工作,而需要停顿的初始标记阶段和重新标记阶段进行速度又很快,因此从总体上来说,CMS收集器内存回收是与用户线程并发执行的。

优点: 停顿时间短,吞吐量大,并发收集
缺点:
(1)对CPU资源非常敏感。

虽然在并发阶段并不会导致用户线程停顿,但是因为垃圾回收线程占用了CPU资源从而会导致用户线程运行速度变慢,会使总的吞吐量降低。

(2)无法收集浮动垃圾。

在并发清除阶段,伴随着用户线程的进行,垃圾对象还会源源不断的产生,但由于这些垃圾对象产生在标记阶段之后,CMS无法在本次GC中收集它们,只能等到下一次GC再清除。

(3)容易产生大量内存碎片。

因为CMS回收器使用的是“标记—清除算法”,因此很容易产生大量的内存碎片。内存碎片过多,将会给大对象的内存分配带来麻烦,往往会出现老年代还有很大的空间剩余却因没有足够大的连续内存空间来分配对象而不得不提前触发一次Full GC。

说明: 在并发清除阶段,因为会有浮动垃圾的出现,因此CMS收集器的触发时机不会像其它老年代收集器一样到老年代几乎被填满以后才被触发,它必须给浮动垃圾预留空间。在JDK 1.5的默认设置下,CMS收集器在老年代使用了68%的内存空间时就会被激活,而到了JDK 1.6,CMS收集器的启动阈值已经达到92%,当然该参数可通过-XX CMSInitiatingOccupancyFraction的值来设置百分比,以达到更高的效率。当CMS收集器运行期间,预留空间的大小无法满足应用程序的需要时,就会出现一次“Concurren Mode Failure”失败,这时候虚拟机将启动后备预案:临时启用Serial Old收集器来进行老年代的垃圾回收,这样停顿时间就很长了。
适用场景: 互联网站或B/S系统的服务端(希望系统停顿时间短,响应速度快)

七、G1收集器

G1收集器是当今收集器技术发展的最前沿成果。它是一款面向服务器端的收集器,是为了取代CMS而设计的一款收集器。
特点:

  • 并发与并行:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU或者多个CPU核心来降低Stop-The-World停顿的时间。部分收集器原来因为要GC需要停顿的动作,G1仍可通过并发的方式让应用程序继续运行。
  • 分代收集:虽然G1收集器不需要与其它收集器配合就能独立管理整个GC堆,但是它仍然需要采用不同的方式处理新创建的对象和存活了一段时间的对象,以获取更好的收集效果。
  • 空间整合:与CMS采用的“标记—清除”算法不同,G1收集器整体上看是基于“标记—整理”算法,但局部上则是采用“复制”算法实现的。无论如何,这两种算法都意味着G1在进行垃圾回收时不会产生内存碎片的问题。这种特性适合程序长期运行,分配大对象时不会因为没有足够大的连续空间而提前触发下一次GC。
  • 可预测的停顿:这是G1相对于CMS的另一大优势。G1除了追求地停顿以外,还可以建立可预测停顿时间模型,能够让使用者指定在一段长度为N毫秒的时间片段内,消耗在垃圾回收上的时间不得超过M毫秒。
    G1对内存的划分及工作原理:前面我们提及到局部的概念。G1收集器不再是在整个新生代或者老年代进行垃圾收集,它把整个Java堆分为大小相等的独立区域(Region),虽然还保留这新生代和老年代的概念,但是新生代和老年代不再是物理隔离的了,他们都是一部分Region(不需要连续)集合。如图所示:
    在这里插入图片描述
    注:除了 Eden、Survivor、Old以外,G1还分了Humongous区用于存放较大对象,如果一个Region存放不下,会寻找连续的Humongous区存储。

G1收集器之所以能够建立可预测的停顿时间模型,就是因为它避免了在整个Java堆的全区域进行垃圾收集。G1跟踪每个Region中的垃圾堆积的价值大小(回收所获取空间的大小和回收所需要时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间(用户设定的收集时间)优先回收价值最大的Region区域。这种把Java堆划分区域以及具有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。

G1收集器的 运作步骤

  1. 初始标记:Stop The World,标记GC Root能直接关联到的对象,时间较短。
  2. 并发标记:根据GC Root进行可达性分析,标记存活的对象,时间较长但可与用户线程并发执行。
  3. 最终标记:修改并发标记期间由于用户线程运行而产生的对象标记产生变动的一部分标记记录,可并行执行。
  4. 筛选回收:先对每个区域的Region的回收价值和成本进行排序,再根据用户所期望的GC停顿时间来指定GC计划。这个阶段其实也可以做到并发执行,但是因为只是回收一部分Region并且停顿时间是用户可控的,而且停顿用户线程还可以提高回收效率,就做成了Stop The World。
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_42798661/article/details/93385124
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢