当前位置: 首页 > 科技观察

你知道常见的垃圾收集器有哪些吗?

时间:2023-03-18 14:31:32 科技观察

本文转载自微信公众号《Java极客技术》,作者鸭血范。转载本文请联系Java极客技术公众号。作为一个Java开发者,垃圾回收器是面试过程中经常被问到的一个问题。随着Java的发展,垃圾收集器也经历了很多的发展。知名的垃圾收集器主要有以下几种。串行单线程新生代复制算法垃圾收集器;SerialOld垃圾收集器是一种单线程老年代标记整理算法;ParNew垃圾收集器是Serial的多线程实现,使用复制算法实现;ParallelScavenge垃圾收集器,是一种高效的多线程复制算法;ParallelOld垃圾收集器是ParallelScavenge的老年代多线程标记清除算法;CMS垃圾回收器是一种多线程的mark-and-sweep算法,后面会详细介绍;G1垃圾收集器是一种高吞吐量垃圾收集器。回收算法在介绍垃圾收集器之前,我们先了解一下垃圾收集器背后的算法。每个垃圾收集器都是特定算法的实现。不同的垃圾收集器只是背后有不同的算法。下面就简单介绍一下吧。具体算法。标记清除标记清除算法是一种先标记后清除的算法。第一次扫描时,先标记所有需要清理的内存,一次性标记所有需要回收的内存并清理。该算法简单但效率低,内存碎片严重。一旦内存碎片化严重,就会浪费内存,无法分配更大的对象。复制算法复制算法的实现比较简单明了。就是把内存霸道的分成两部分,平时使用的时候只用到其中的一部分。当需要进行GC时,将存活的对象复制到另一部分,然后清理所有使用过的内存。这个算法可以解决碎片问题,但是缺点也很明显,就是浪费内存,有一半的内存不能用。标记算法既然标记清除算法和复制算法各有优缺点,我们自然会想到是否可以将这两种算法结合起来,于是出现了标记清除算法。标记阶段和mark-and-clear算法一样,先标记需要回收的部分,但是清除阶段不是直接清除,而是将存活的对象移动到内存的一端,然后清除休息。标记算法虽然可以解决上述两种算法的部分问题,但仍然需要先标记再移动,整体效率仍然较低。分代恢复算法分代恢复算法是目前应用广泛的一种算法。这不是什么新算法,只是划分内存而已。不同的内存区域使用不同的算法。根据对象的存活时间,内存分为新生代和老年代,其中新生代包括Eden区和S0、S1。复制算法用于新生代。分配对象内存时,只会使用Eden和S0区域。当GC发生时,存活的对象会被复制到S1区,然后循环复制。当一个对象在15次GC之后仍然存活时,该对象将进入老年代。老年代使用标记算法,因为每次回收的对象较少。上面虽然说了几种垃圾收集器,但是目前主流的垃圾收集器只有CMS和G1。下面就和大家聊聊这两个垃圾收集器吧。CMS垃圾收集器CMS代表ConcurrentMarkSweepConcurrentMarkSweepGarbageCollector。CMS是一个以获取最短停顿时间为目的的垃圾收集器。说到暂停时间,我们都知道任何一个垃圾收集器在工作的时候都会有STW。StoptheWorld停止用户进程。这只是业务不能接受的,但是市面上所有的垃圾收集器都无法避免这个问题,只能最大限度的优化减少停顿时间。尽管CMS被称为并发垃圾收集器,但它并不是完全并发的。从名字我们可以看出它是使用标记-清除算法实现的。整个实现过程分为五个步骤:初始标记:暂停所有线程从可达性分析中标记对象,这也是CMS垃圾收集器的第一个STW;并发标记:并发标记时GC线程和用户线程同时存在,在这个过程中会记录所有可达的线程,但是这个过程结束后,会产生新的引用更新,因为用户线程一直在运行,表示需要下一步;并发预清洗:这个阶段用户线程和GC线程同时运行,GC线程会执行预清洗Cleanup动作;重标记:重标记阶段会将用户线程挂起,纠正上一次并发标记过程中用户线程引起的更新。这个时间会比初始标记时间长,但会比并发标记时间短;concurrentCleanup:所有需要清理的对象都被标记后,才会进行最后一步的清理。清理时用户线程可以继续运行,GC线程只清理标记区域。G1垃圾收集器G1全称Garbage-First是一个面向服务器的垃圾收集器,它通过将堆内存划分为多个区域来实现可预测的暂停时间模型。在G1中,新生代和老年代不再在物理上分开,而是划分为Region。正是这种可预测的时间暂停模型使G1成为高吞吐量的垃圾收集器。G1可以充分利用CPU,在多核环境下可以缩短STW时间。G1垃圾收集器的整个实现过程分为四个步骤:初始标记:通过可达性分析标记GCRoots直接相关的对象。这个阶段需要像CMS一样的STW;并发标记:并发标记通过GCRoots对象找到存活对象,GC线程和用户线程在这个阶段同时运行,这个阶段的时间比初始标记要长;finalmarking:finalmarking和CMS的re-marking一样,也是为了纠正用户线程继续运行导致的并发标记过程产生新的referenceupdate;这里也需要STW;Filter回收:这里的Filter回收会对每个Region的回收成本进行排序,并根据用户预期的停顿时间制定回收计划,这也是一个可预测的停顿时间模型,这个阶段GC线程与用户线程并发运行。总结虽然说Java开发不需要程序员手动创建和回收内存,但是理解和掌握垃圾收集器是每个Java程序员必须掌握的。也很有帮助。本文由阿芬本人研究整理。部分资料参考了网络,分享给大家,帮助大家共同成长。