《深入理解java虚拟机》笔记3——7种垃圾收集器

2019-01-11  本文已影响5人  Meandni

2019大三的寒假计划——利用在公司每天早起的时间读书,第一本是周志明老师的《深入理解Java虚拟机——JVM高级特性与最佳实践》,这一系列是通过对原文的拜读与自己理解加上网络上的资料文章整理出的读书笔记。

如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。**Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商、版本的虚拟机所提供的垃圾收集器都可能会有很大差别,并且一般都会提供参数供用户根据自己的应用特点和要求组合出各个年代所使用的收集器。接下来讨论的收集器基于JDK1.7 Update 14 之后的HotSpot虚拟机(在此版本中正式提供了商用的G1收集器,之前G1仍处于实验状态),该虚拟机包含的所有收集器如下图所示:

<div align="center"> <img src="http://pic.yupoo.com/meandni/e8793494/27df7474.jpg" width=""/> </div>

以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。

相关概念

并行和并发

吞吐量(Throughput)

吞吐量就是CPU用于运行用户代码的时间CPU总消耗时间的比值,即

吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)。

假设虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。

Minor GC 和 Full GC

各收集器阐述

1. Serial 收集器

<div align="center"> <img src="http://pic.yupoo.com/meandni/5c861f07/b1ac068e.jpg" width=""/> </div>

Serial 翻译为串行,也就是说它以串行的方式执行。

它是单线程的收集器,只会使用一个线程进行垃圾收集工作。

它的优点是简单高效,对于单个 CPU 环境来说,由于没有线程交互的开销,因此拥有最高的单线程收集效率。

它是 Client 模式下的默认新生代收集器,因为在该应用场景下,分配给虚拟机管理的内存一般来说不会很大。Serial 收集器收集几十兆甚至一两百兆的新生代停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿是可以接受的。

2. ParNew 收集器

<div align="center"> <img src="http://pic.yupoo.com/meandni/a5c6e277/481e1ca1.jpg" width=""/> </div>

它是 Serial 收集器的多线程版本。

是 Server 模式下的虚拟机首选新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合工作。

默认开启的线程数量与 CPU 数量相同,可以使用 -XX:ParallelGCThreads 参数来设置线程数。

3. Parallel Scavenge 收集器

与 ParNew 一样是多线程收集器。

其它收集器关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,它被称为“吞吐量优先”收集器。这里的吞吐量指 CPU 用于运行用户代码的时间占总时间的比值。

停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,适合在后台运算而不需要太多交互的任务。

缩短停顿时间是以牺牲吞吐量和新生代空间来换取的:新生代空间变小,垃圾回收变得频繁,导致吞吐量下降。

可以通过一个开关参数打开 GC 自适应的调节策略(GC Ergonomics),就不需要手工指定新生代的大小(-Xmn)、Eden 和 Survivor 区的比例、晋升老年代对象年龄等细节参数了。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。

4. Serial Old 收集器

<div align="center"> <img src="http://pic.yupoo.com/meandni/14f72c5c/367020d3.jpg" width=""/> </div>

是 Serial 收集器的老年代版本,也是给 Client 模式下的虚拟机使用。如果用在 Server 模式下,它有两大用途:

5. Parallel Old 收集器

<div align="center"> <img src="http://pic.yupoo.com/meandni/2d1989e5/6e965e83.jpg" width=""/> </div>

是 Parallel Scavenge 收集器的老年代版本。

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

6. CMS 收集器

<div align="center"> <img src="http://pic.yupoo.com/meandni/14f72c5c/367020d3.jpg" width=""/> </div>

CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。

分为以下四个流程:

在整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,不需要进行停顿。

具有以下缺点:

7. G1 收集器

G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能。HotSpot 开发团队赋予它的使命是未来可以替换掉 CMS 收集器。

堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。

<div align="center"> <img src="http://pic.yupoo.com/meandni/400d294e/1d022e13.png" width="600"/> </div>

G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。

<div align="center"> <img src="http://pic.yupoo.com/meandni/5393369d/5f8cbd42.png" width="600"/> </div>

通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。

每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。

<div align="center"> <img src="http://pic.yupoo.com/meandni/ce8ef9fc/10c8999f.jpg" width=""/> </div>

如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤:

具备如下特点:

总结

收集器 串行、并行or并发 新生代/老年代 算法 目标 适用场景
Serial 串行 新生代 复制算法 响应速度优先 单CPU环境下的Client模式
Serial Old 串行 老年代 标记-整理 响应速度优先 单CPU环境下的Client模式、CMS的后备预案
ParNew 并行 新生代 复制算法 响应速度优先 多CPU环境时在Server模式下与CMS配合
Parallel Scavenge 并行 新生代 复制算法 吞吐量优先 在后台运算而不需要太多交互的任务
Parallel Old 并行 老年代 标记-整理 吞吐量优先 在后台运算而不需要太多交互的任务
CMS 并发 老年代 标记-清除 响应速度优先 集中在互联网站或B/S系统服务端上的Java应用
G1 并发 both 标记-整理+复制算法 响应速度优先 面向服务端应用,将来替换CMS

参考资料

原文博客:

《深入理解java虚拟机》笔记3——7种垃圾收集器

上一篇 下一篇

猜你喜欢

热点阅读