在前面,我们已经了解了JVM的分代收集,知道JVM垃圾收集在新生代主要采用标记-复制算法,在老年代主要采用标记-清除和标记-整理算法。接下来,我们看一看JDK默认虚拟机HotSpot的一些垃圾收集器的实现。
1、常见垃圾回收器首先来看一下JDK 11之前全部可用的垃圾收集器。
HotSpot虚拟机
图中列出了七种垃圾收集器,连线表示可以配合使用,所在区域表示它是属于新生代收集器或是老年代收集器。
这里还标出了垃圾收集器采用的收集算法,G1收集器比较特殊,整体采用标记-整理算法,局部采用标记-复制算法,后面再细讲。
1.1、Serial收集器Serial收集器是最基础、历史最悠久的收集器。
如同它的名字(串行),它是一个单线程工作的收集器,使用一个处理器或一条收集线程去完成垃圾收集工作。并且进行垃圾收集时,必须暂停其他所有工作线程,直到垃圾收集结束——这就是所谓的“Stop The World”。
Serial/Serial Old收集器的运行过程如图:
Serial/Serial Old收集器运行示意图
1.2、ParNew收集器ParNew收集器实质上是Serial收集器的多线程并行版本,使用多条线程进行垃圾收集。
ParNew收集器的工作过程如图所示:
ParNew/Serial Old收集器运行示意图
这里值得一提的是Par是Parallel(并行)的缩写,但需要注意的是,这个并行(Parallel)仅仅是描述同一时间多条GC线程协同工作,而不是GC线程和用户线程同时运行。ParNew垃圾收集也是需要Stop The World的。
1.3、Parallel Scavenge收集器Parallel Scavenge收集器是一款新生代收集器,基于标记-复制算法实现,也能够并行收集。和ParNew有些类似,但Parallel Scavenge主要关注的是垃圾收集的吞吐量。
所谓吞吐量指的是运行用户代码的时间与处理器总消耗时间的比值。这个比例越高,证明垃圾收集占整个程序运行的比例越小。
吞吐量
Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量:
由于与吞吐量关系密切,Parallel Scavenge收集器也经常被称作“吞吐量优先收集器”。
1.4、Serial Old收集器Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法。
Serial Old收集器的工作过程如图:
Serial/Serial Old收集器运行示意图
1.5、Parallel Old收集器Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。
Parallel Scavenge/Parallel Old收集器运行示意图
1.6、CMS收集器CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,同样是老年代的收集齐,采用标记-清除算法。
CMS收集齐的垃圾收集分为四步:
❝
涉及到了多次标记的过程,这里插入一点三色抽象的知识。三色抽象用来描述对象在垃圾收集过程中的状态。
通常白色代表对象未被扫描到,灰色表示对象被扫描到但未被处理,黑色表示对象及其后代已被处理。在CMS的标记和清除过程中就用到了这种抽象,详细的可以查看参考【5】。
❞
Concurrent Mark Sweep收集器运行示意图如下:
Concurrent Mark Sweep收集器运行示意图
优点:CMS最主要的优点在名字上已经体现出来——并发收集、低停顿。
缺点:CMS同样有三个明显的缺点。
Garbage First(简称G1)收集器是垃圾收集器的一个颠覆性的产物,它开创了局部收集的设计思路和基于Region的内存布局形式。
虽然G1也仍是遵循分代收集理论设计的,但其堆内存的布局与其他收集器有非常明显的差异。以前的收集器分代是划分新生代、老年代、持久代等。
垃圾分代区域
G1把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。收集器能够对扮演不同角色的Region采用不同的策略去处理。
G1 Heap Regions
这样就避免了收集整个堆,而是按照若干个Region集进行收集,同时维护一个优先级列表,跟踪各个Region回收的“价值,优先收集价值高的Region。
G1收集器的运行过程大致可划分为以下四个步骤:
G1收集器运行示意图
相比CMS,G1的优点有很多,可以指定最大停顿时间、分Region的内存布局、按收益动态确定回收集。
只从内存的角度来看,与CMS的“标记-清除”算法不同,G1从整体来看是基于“标记-整理”算法实现的收集器,但从局部(两个Region 之间)上看又是基于“标记-复制”算法实现,无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,垃圾收集完成之后能提供规整的可用内存。
2、前沿垃圾回收器2.1、ZGC收集器在JDK 11当中,加入了实验性质的ZGC。它的回收耗时平均不到2毫秒。它是一款低停顿高并发的收集器。
与CMS中的ParNew和G1类似,ZGC也采用标记-复制算法,不过ZGC对该算法做了重大改进:ZGC在标记、转移和重定位阶段几乎都是并发的,这是ZGC实现停顿时间小于10ms目标的最关键原因。
ZGC垃圾回收周期
ZGC虽然在JDK 11还处于实验阶段,但由于算法与思想是一个非常大的提升,未来前景相信还是很广阔的。
3、垃圾收集器选择3.1、收集器选择权衡垃圾收集器的选择需要权衡的点还是比较多的——例如运行应用的基础设施如何?使用JDK的发行商是什么?等等……
这里简单地列一下上面提到的一些收集器的适用场景:
设置垃圾收集器(组合)的参数如下:
「新生代」「老年代」「JVM 参数」IncrementalIncremental-Xincgc「Serial」「Serial」「-XX: UseSerialGC」Parallel ScavengeSerial-XX: UseParallelGC -XX:-UseParallelOldGCParallel NewSerialN/ASerialParallel OldN/A「Parallel Scavenge」「Parallel Old」「-XX: UseParallelGC -XX: UseParallelOldGC」Parallel NewParallel OldN/ASerialCMS-XX:-UseParNewGC -XX: UseConcMarkSweepGCParallel ScavengeCMSN/A「Parallel New」「CMS」「-XX: UseParNewGC -XX: UseConcMarkSweepGC」「G1」
「-XX: UseG1GC」
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved