这方面的知识推荐看《深入理解Java虚拟机》
一、JVM垃圾收集器
- Serial收集器(复制算法): 新生代单线程收集器,标记和清理都是单线程,优点是简单高效;
- ParNew收集器 (复制算法): 新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;
- Parallel Scavenge收集器 (复制算法): 新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景;
- Serial Old收集器 (标记-整理算法): 老年代单线程收集器,Serial收集器的老年代版本;
- Parallel Old收集器 (标记-整理算法): 老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本;
- CMS(Concurrent Mark Sweep)收集器(标记-清除算法): 老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间。
- G1(Garbage First)收集器 (标记-整理算法): Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。
垃圾收集器均会 Stop-the-World
(1)CMS
CMS(Concurrent Mark Sweep) 回收器是在 最短回收停顿时间
为前提的回收器,属于 多线程回收器,用于老年代
的垃圾收集,采用 标记-清除
算法。
- 初始标记
初始标记 仅仅是标记 GC Roots 内直接关联
的对象。这个阶段 速度很快,需要Stop the World
。 - 并发标记
并发标记 进行的是 GC Tracing,从 GC Roots 开始对堆进行 可达性分析,找出 存活对象。 - 重新标记
重新标记 阶段为了 修正 并发期间由于 用户进行运作 导致的标记变动
的那一部分对象的 标记记录。这个阶段的 停顿时间 一般会比 初始标记阶段 稍长一些,但远比 并发标记 的时间短,也需要Stop The World
。 - 并发清除
并发清除 阶段会清除垃圾对象。
在整个过程中,CMS 回收器的 内存回收
基本上和 用户线程
并发执行,如下所示:
由于 CMS 回收器 并发收集、停顿低
,因此有些地方称为 并发低停顿回收器(Concurrent Low Pause Sweep Collector)。
CMS缺点
-
CMS回收器对CPU资源非常依赖
CMS 回收器过分依赖于 多线程环境,默认情况下,开启的 线程数 为(CPU 的数量 + 3)/ 4
,当 CPU 数量少于 4 个时,CMS 对 用户查询 的影响将会很大,因为他们要分出一半的运算能力去 执行回收器线程; -
CMS回收器无法清除浮动垃圾
由于 CMS 回收器 清除已标记的垃圾 (处于最后一个阶段)时,用户线程 还在运行,因此会有新的垃圾产生。但是这部分垃圾 未被标记,在下一次 GC 才能清除,因此被成为 浮动垃圾。
由于 内存回收 和 用户线程 是同时进行的,内存在被 回收 的同时,也在被 分配。当 老生代 中的内存使用超过一定的比例时,系统将会进行 垃圾回收;当 剩余内存 不能满足程序运行要求时,系统将会出现Concurrent Mode Failure
,临时采用Serial Old 算法
进行 清除,此时的 性能 将会降低。 -
垃圾收集结束后残余大量空间碎片
CMS 回收器采用的标记清除算法
,本身存在垃圾收集结束后残余 大量空间碎片 的缺点。CMS 配合适当的 内存整理策略,在一定程度上可以解决这个问题。
(2)G1
G1 是 JDK 1.7 中正式投入使用的用于取代 CMS 的 压缩回收器。没有在物理上隔断 新生代
与 老生代
,但是仍然属于 分代垃圾回收器
。G1 仍然会区分