前面的算法都是理论知识,而垃圾收集器是这些算法实现。
不同版本的 JDK 选择的垃圾收集器也可能不同,我们在命令行查看安装的 JDK 的默认垃圾收集器,我这里是在 Windows 的 cmd 中输入 java -XX:+PrintCommandLineFlags -version
,执行结果如下图。
查看默认的垃圾回收器.jpg
我的机器上装的是 JDK8,ParallelGC 就是 JDK 默认采用的垃圾收集器组合,包括 PS Scavenge(新生代收集器) 和 PS MarkSweep(老生代收集器),也可以通过下面的代码打印出正在使用的垃圾收集器。
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;
public class GCTest {
public static void main(String args[]) {
List<GarbageCollectorMXBean> list = ManagementFactory.getGarbageCollectorMXBeans();
for(GarbageCollectorMXBean bean : list) {
System.out.println(bean.getName());
}
}
}
这里也给出一张垃圾收集器组合相关的常用参数表。
参数 | 描述 |
---|---|
UseSerialGC | 虚拟机运行在 Client 模式下的默认值,使用 Serial + Serial Old 收集器组合回收内存 |
UseParNewGc | 使用 ParNew + Serial Old 收集器组合回收内存 |
UseConcMarkSweepGC | 使用 ParNew + CMS + Serial Old 收集器组合回收内存 |
UseParallelGC | 虚拟机运行在 Server 模式下的默认值,使用 PS Parallel + Serial Old(PS MarkSweep)收集器组合回收内存 |
为什么不是一个垃圾收集器,而是垃圾收集器组合呢?在前面,我们提到分代收集算法将堆内存区域再次划分,综合了其他算法的优点,所以主流的虚拟机也是根据不同年代的内存区域,使用不同算法实现的收集器,下面将逐一介绍这些垃圾收集器。
在介绍收垃圾收集器之前,我们先想象一个打扫卫生的场景,如果在一边有人打扫,一边又有人扔垃圾,那么卫生能打扫干净吗?答案肯定是不能的。那么怎样才能打扫干净呢?你可能会说打扫的时候不能有人再扔垃圾了,没错就是这样,在 Java 虚拟机中,垃圾收集器就像打扫卫生的人,可能有一个也可能有多个,对应也就是单线程和多线程,其他线程就像是扔垃圾的人。垃圾收集器打扫卫生肯定也是需要时间,在这个时间不能有其他线程 “扔垃圾”,也即是暂停其他线程使用直到垃圾收集结束。在 Java 虚拟机中,这种事情叫做 “Stop The Word”,简称 STW。计算机运行速度很快,如果把 STW 的时间缩到很短,人们根本察觉不出来。理解了这些,下面就来想看看每种垃圾回收器的介绍。
1、Serial 收集器
从名字上看是串行的意思,这个收集器是一个单线程的新生代收集器。Serial 采取 “复制算法” 实现,如果是在单 CPU 环境下,Serial 收集器没有线程交互的开销,理论上是可以获得最高的单线程执行效率,STW 的时间也可以控制在几十到几百毫米内,这个时间是完全可以接受的。
2、Serial Old 收集器
Serial Old 收集器 是 Serial 收集器的老年代版本,同样也是一个单线程收集器,使用 “标记-整理算法”。由于 PS MarkSweep 收集器与 Serial Old 收集器的实现非常接近,在官方的许多资料中都是直接以 Serial Old 代替 PS MarkSweep 的,所以 Ps MarkSweep 收集器可以看做是 Serial Old 收集器的别名。
3、ParNew 收集器
ParNew 收集器实际上就是 Serial 收集器的多线程版本,收集算法、STW、对象分配的规则、回收策略等都与 Serial 收集器完全一样,两者相同的代码很多。ParNew 收集器虽然有多线程优势,但在单 CPU 和多 CPU 环境下,效果并不一定会比 Serial 好,在单 CPU 环境下是肯定不如的 Serial 的。看起来人多力量大,但由于线程交互开销的时间,效果并不如人意,多线程的好处在于更高效率的利用 CPU ,提高 CPU 的吞吐量,也就是 CPU 空闲的时间很少。
**4、Parallel Scavenge收集器 **
Parallel Scavenge收集器和 ParNew 收集器很像,也是一个新生代收集器,也是使用复制算法,并且还是并行的多线程的收集器。相比于 ParNew 收集器,Parallel Scavenge收集器可以增加精准的控制 CPU 的吞吐量和 STW 的时间,对于交互不多任务可以更快的完成。
**5、Parallel Old 收集器 **
Parallel Old 收集器是 Parallel Scavenge 收集器的老年代版本,使用多线程和 “标记-整理算法”。在 Parallel Old 收集器出现之间,选择了 Parallel Scavenge 收集器作为新生代的收集器,就只能选择 Serial Old 收集器作为老生代收集器,这样肯定就是对多 CPU 的浪费,所以 Parallel Scavenge收集器 + Parallel Old 收集器,对于多 CPU 环境吞吐量要求高的环境,算是强强联合。
6、CMS 收集器
CMS (Concurrent Mark Sweep)收集器从英文名字上看就是基于 “标记-清除算法” 实现的,并且还有并发的特征,它是一种以缩短 STW 的时间为目标的收集器,对于一些重视服务响应速度的网站,肯定是 STW 越短,用户体验越好了。但是缺点是会在垃圾收集结束后产生大量的空间碎片,这点从使用的算法也可以看出来。
7、G1 收集器
G1 收集器是目前最前沿的收集器,它是基于 "标记-整理算法" 实现的,所以不会产生内存碎片,并且也可以精准的控制 STW 的时间。G1 收集器对于新生代和老年代都是适用的,优先回收垃圾最多的区域。
几种垃圾收集器的组合如下图所示。
垃圾回收器组合.jpg