HotSpot 虚拟机中的 7 个垃圾收集器:
(连线代表两种收集器可以搭配使用)
- 串行:垃圾回收线程和用户线程交替进行,并且垃圾回收线程是单线程的。在垃圾回收过程中需要暂停用户线程(Stop The World)。GC线程是单线程的并非说明环境是单CPU下,在多核CPU下进行GC的时候只会使用单核CPU。
- 并行(Parallel):多条垃圾回收线程同时执行,此时用户线程处于暂停(Stop The World)。这里肯定是在多核CPU环境下。
- 并发(Concurrent):垃圾收集器和用户程序同时执行。除了 CMS 和 G1 之外,其它垃圾收集器都是以串行的方式执行。
Serial收集器
Serial 收集器是一个单线程的收集器,串行,是虚拟机运行在 Client 模式下的默认新生代收集器。
他只会使用一个CPU或一条收集线程去完成垃圾回收。在进行垃圾收集时,必须暂停掉其他所有工作线程(Stop The World, STW),直到它收集结束。
它的优点是简单高效,对于单个 CPU 环境来说,由于没有线程交互的开销,因此拥有最高的单线程收集效率。
它是 Client 模式下的默认新生代收集器,因为在用户的桌面应用场景下,分配给虚拟机管理的内存一般来说不会很大。Serial 收集器收集几十兆甚至一两百兆的新生代停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿是可以接受的。
ParNew收集器
它是 Serial 收集器的多线程版本,并行。
是虚拟机运行在 Server 模式下的首选新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合工作。
默认开启的线程数量与 CPU 数量相同,-XX:ParallelGCThreads
可以设置线程数。
Parallel Scavenge收集器
与 ParNew 一样是多线程收集器。
其它收集器关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,它被称为“吞吐量优先”收集器。这里的吞吐量指 CPU 用于运行用户代码的时间占总时间的比值。
停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
控制参数:
-XX:MaxGCPauseMillis
设置最大垃圾收集停顿时间-XX:GCTimeRatio
设置吞吐量大小开关参数:
-XX:+UseAdaptiveSizePolicy
打开 GC 自适应的调节策略(GC Ergonomics)不需要手动指定新生代的大小(-Xmn)、Eden 和 Survivor 区的比例、晋升老年代对象年龄等细节参数。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。自适应调节策略是parallel Scavenge收集器和ParNew收集器的重要区别
Serial Old收集器
Serial收集器的老年代版本,也是给 Client 模式下的虚拟机使用。
如果用在 Server 模式下,它有两大用途:
- 在 JDK 1.5 以及之前版本(Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用。
- 作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。
Parallel Old 收集器
Parallel Old 是 Parallel Scavenge 收集器的老年代版本,使用多线程和“标记-整理”算法。
在注重吞吐量和CPU资源敏感的场合,都可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器。
CMS收集器
CMS(Concurrent Mark Sweep,并发-标记-清除),是HotSpot虚拟机中第一个并发收集器,实现了让垃圾收集线程和用户线程同时工作。
CMS是一种以获取最短回收停顿时间为目标的收集器。
运作过程四个步骤:
- 初始标记: 仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿(Stop The World)。
- 并发标记: 进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿。
- 重新标记: 为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿(Stop The World)。
- 并发清除: 不需要停顿。
整个过程中,耗时最长的并发标记和表发清除过程收集器线程可以与用户线程一起工作,不需要停顿。
优点:
并发收集、低停顿。CMS也被称为并发低停顿收集器。
缺点:
总吞吐量低。
- 在并发阶段,CMS收集器会因为占用了一部分线程(CPU资源)而导致应用程序变慢,总吞吐量因此降低。CMS默认的回收线程数是(CPU数量+3)/4。
无法处理浮动垃圾。
- 浮动垃圾:在并发清除阶段由于用户线程继续运行而产生的垃圾,这部分垃圾只能到下一次 GC 时才能进行回收。
- 由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS。
收集结束后产生大量空间碎片。
- 标记 - 清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配大对象,不得不提前触发一次 Full GC。
G1收集器
G1是一种面向服务器端应用的垃圾收集器。
在G1之前的收集器收集的范围是整个新生代或老年代,G1收集器将整个堆划分为多个大小相等的独立区域(Region),仍然保留新生代和老年代的概念,但二者不再物理隔离了,他们都是一部分Region的集合。
Region 之间的对象引用通过 Remembered Set 实现。每个 Region 都有一个 Remembered Set,在可达性分析过程中可以避免全堆扫描。
通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),跟踪各个 Region 里面的垃圾堆积的价值大小,并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
G1收集器的特点
- 空间整合:G1是基于“标记 - 整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复制”算法实现的,这意味着运行期间不会产生内存空间碎片。分配大对象时不会因为找不到连续的内存空间而提前触发下一次GC。
- 可预测的停顿:G1和CMS都追求降低停顿时间,但G1还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为 M 毫秒的时间片段内,消耗在 GC 上的时间不得超过 N 毫秒。
G1收集器的运行步骤
- 初始标记:仅仅标记一下GC Roots能直接关联到的对象,该阶段需要停顿线程,但耗时很短。
- 并发标记:从GC Roots开始进行可达性分析,找出存活的对象。该阶段耗时较长,与用户程序并发进行。
- 最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面,最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中。这阶段需要停顿线程,但是可并行执行。
- 筛选回收:首先对各个 Region 中的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。