JVM 垃圾收集器
前言
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。Java 虚拟机规范并没有规定垃圾收集器应该如何实现,不同产商会提供不同的垃圾收集器,一般会给出参数来让用户根据应用的特点来组合各个年代使用的收集器,
主要有以下垃圾收集器:
经典垃圾收集器.png-
在新生代工作的垃圾回收器:Serial, ParNew, ParallelScavenge
-
在老年代工作的垃圾回收器:CMS,Serial Old, Parallel Old
-
同时在新老生代工作的垃圾回收器:G1
图片中的垃圾收集器如果存在连线,则代表它们之间可以配合使用。
Serial收集器
Serial收集器一个单线程工作的新生代收集器,它只会使用一个处理器或一条收集线程去完成垃圾收集工作,它进行垃圾收集时,必须暂停其他所有工作线程(即STW),直到它收集结束。
Serial收集器对于运行在客户端模式下的虚拟机来说是一个很好的选择
优点:
-
简单高效
-
没有线程交互开销
-
停顿时间短
缺点:
-
必须停顿其他工作线程
-
单线程
ParNew收集器
ParNew 收集器是 Serial 收集器的多线程并行版本,除了使用多线程,其他像收集算法,STW,对象分配规则,回收策略与 Serial 收集器完成一样,在底层上,这两种收集器也共用了相当多的代码。
ParNew收集器 许多运行在 Server 模式下的虚拟机的首选新生代收集器。
除了 Serial 收集器,只有它能与 CMS 收集器配合工作
优点:
-
多线程并行
-
默认线程数与CPU数相同
缺点:
- 单CPU下效率会比Serial差
Parallel Scavenge收集器
Parallel Scavenge收集器也是一款新生代收集器,它同样是基于标记-复制算法
实现的收集器,也是能够并行收集的多线程收集器。
Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量
。
Parallel Scavenge 收集器主要适合在后台运算而不需要太多交互的分析任务。
吞吐量:处理器用于运行用户代码的时间与处理器总消耗时间的比值。
Serial Old收集器
Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法。
Serial Old 的主要意义在于给 Client 模式下的虚拟机使用,如果在 Server 模式下,则它还有两大用途:一种是在 JDK 1.5 及之前的版本中与 Parallel Scavenge 配合使用,另一种是作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用
Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程并发
收集,基于标记-整理算法实现。这个收集器是直到JDK 6时才开始提供的。
CMS收集器
CMS 收集器是以实现最短 STW 时间为目标的收集器。
如果关注服务的响应速度,希望系统停顿时间尽可能短,以给用户带来良好的交互体验,CMS是个不错的选择。
老年代主要用标记整理法,而 CMS 虽然工作于老年代,但采用的是标记清除法。
运作过程:
-
初始标记:需要STW,标记GC Roots能直接关联到的对象,速度很快;
-
并发标记:GC Roots Tracing过程(可达性分析);
-
重新标记:需要STW,修正并发标记期间因用户线程继续运行而导致标记产生变动的对象的标记记录。
-
并发清除:清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。
优点:
-
并发收集
-
低停顿
缺点:
-
对CPU资源敏感,占用CPU,导致应用程序变慢,降低总吞吐量
-
不能处理“浮动垃圾”
-
采用标记——清除算法,会产生大量不连续的空间碎片
-
不能等老年代满了再回收,必须预留一部分空间给应用程序使用,默认占满92%就触发回收
-
CMS运行期间预留的内存无法满足程序分配新对象的需要,就会出现一次“并发失败”(Concurrent Mode Failure),临时启用Serial Old收集器来重新进行老年代的垃圾收集,停顿时间长。
浮动垃圾:在标记过程后产生的垃圾,CMS无法当次处理,需要等到下一次GC
Garbage First (G1)收集器
G1 收集器是面向服务端的垃圾收集器,被称为驾驭一切的垃圾回收器。
整体上看是使用标记——整理算法,对于两个Region来看是标记——复制算法。
G1 收集器把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间,每一代都使用了 n 个不连续的大小相同的 Region,每个Region占有一块连续的虚拟内存地址。
Region中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。
运作过程:
-
初始标记:标记GC Roots能直接关联的对象;
-
并发标记:不需要STW,GC Roots Tracing过程(可达性分析);
-
最终标记:对用户线程做另一个短暂的暂停,用于处理并发阶段结束后遗留下来的最后那少量的SATB记录;
-
筛选回收:对各个Region的回收价值和成本排序,根据用户期望的GC停顿时间制定回收计划。
优点:
-
能与应用程序线程并发执行
-
整理空闲空间更快
-
不会产生内存碎片
-
分代回收,不需要其他GC收集器配合,独立管理新生代和老年代
-
可预测停顿时间:可以指定长度为M毫秒的时间片内,消耗在GC上的时间不超过N毫秒