垃圾收集器
1. Serial 收集器 ★
Serial 收集器最基本、发展历史最悠久的收集器;是一个新生代的单线程收集器(老生代版本Serial Old)。
进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束;即“Stop The World”,实际上是由虚拟机在后台自动发起和自动完成的,在用户不可见的情况下把用户正常工作的线程全部停掉,这对很多应用来说是难以接受的。
-
工作过程
- 在安全点(safepoint)暂停用户线程;
- GC线程运行,新生代采用复制算法;老年代使用标记-整理算法收集垃圾;
- 恢复用户线程。
2. ParNew 收集器
ParNew收集器其实就是Serial收集器的多线程版本,其控制参数、收集算法、Stop The World、对象分配规则、回收策略等都完全一样;
区别是:在新生代的采用多线程进行复制算法回收垃圾;而老年代依然使用单线程。
3. Parallel Scavenge 收集器
Parallel Scavenge 收集器是一个新生代收集器,使用复制算法,同时又是并发的多线程收集器。
4. Serial Old 收集器
Serial Old 是Serial 收集器的老年代版本,同样是一个单线程收集器,使用“标记-整理”算法,
5. Parallel Old 收集器
Parallel Old是Parallel Scavenge 收集器的老年代版本
6. CMS 收集器 ★
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。 目前很大一部分Java应用集中在互联网网站或者B/S系统的服务端上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。
CMS收集器基于“标记-清除”算法实现,整个过程分为4个步骤:
- 初始标记(CMS initial mark)
仅仅标记一下GC Roots能够直接关联到的对象,速度很快 - 并发标记(CMS concurrent mark)
进行GC Roots Tracing的过程(可达性分析) - 重新标记(CMS remark)
为了修正并发标记期间因为用户程序继续运作而导致标记产生变动的那一部分对象的标记记录 - 并发清除(CMS concurrent sweep)
垃圾回收,内存回收过程是与用户线程一起并发执行的。
-
三个缺点
-
CMS收集器对CPU资源非常敏感。默认启动的回收线程数是(CPU数量+3)/ 4。
-
CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理掉它们,只好留到下一次GC时再清理。
-
CMS是一款基于“标记-清除”算法实现的收集器,会产生内存碎片,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数(默认是开启的),用于在CMS收集器顶不住要进行FullGC时开启内存碎片的合并整理过程,内存整理过程是单线程。
7. G1 收集器 ★
特点
- 并行与并发
- 分代收集
- 空间整合
- 可预测的停顿
**将Java堆划分为多个大小相等的独立区域(Region),**虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离,它们都是一部分Region(不需要连续)的集合。
过程:
- 初始标记(Initial mark)
仅仅标记一下GC Roots能够直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,需要停顿线程,但耗时很短。 - 并发标记(Concurrent mark)
从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行。 - 最终标记(Final marking)
为了修正并发标记期间因为用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs中,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set,这阶段需要停顿线程,但是可并行执行。 - 筛选回收(Live Data Counting and Evacuation)
首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段也可以做到与用户程序一起并发执行,因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。