目录
6.CMS收集器(Concurrent Mark Sweep)
java 虚拟机中的垃圾收集器有Serial,ParNew,Parallel Scavenge,Serial Old,Parallel Old, CMS, G1.根据不同的GC代分为:
- 新生代收集器:Serial, ParNew, Parallel Scavenge
- 老年代收集器:Serial Old, Parallel Scavenge,CMS
- 整堆收集器:G1
新生代/老年代收集器搭配使用关系如下图:
图中连线的收集器可以搭配使用:
Serial--Serial Old,Serial-CMS
ParNew--CMS, ParNew--Serial Old
Parallel Scavenge -- Serial Old, Parallel Savenage - Parallel Old.
G1
1.Serial收集器
Serial收集器是最基本,发展历史最悠久的收集器,在JDK1.3之前是虚拟机新生代收集器的唯一选择。Serial收集器是一个新生代的单线程收集器,Serial收集器采用复制算法(参考复制算法原理,以及虚拟机内存分配策略理解)
Serial 收集器的特点:
- 单线程收集器
- 针对新生代
- 采用复制算法。
- 简单高效
Serial收集器使用场景说明
Serial 收集器在虚拟机Client模式下是很好的新生代收集器选择。相比其他收集器来说,Serial收集器是单线程的,没有多线程上下文转换的开销,专心做垃圾收集,所以在Client模式下,限定单个CPU来说,Serial收集器简单高效。
Serial-Serial Old 收集器运行示意图如下:
Serial 收集器设置参数:-XX:UseSerialGC
2.ParNew收集器
ParNew收集器是Serial收集器的多线程版本。同Serial收集器相比,在控制参数,回收算法,对象分配规则等都和Serial收集器完全一致。
ParNew收集器的特点:
- 多线程
ParNew收集器应用场景说明
ParNew 收集器是虚拟机Server模式下新生代收集器的首选,原因如下:
- ParNew与Serial相比,ParNew是多线程的,效率高。
- 如上图所示,除了Serial收集器,只有ParNew收集器可以与老年代的CMS收集器搭配使用。
但是在单个CPU环境中,ParNew收集器的效率不如Serial,因为存在线程的开销。
ParNew收集器的运行示意图如下:
ParNew收集器参数设置:
"-XX:+UseConcMarkSweepGC":指定使用CMS后,会默认使用ParNew作为新生代收集器;
"-XX:+UseParNewGC":强制指定使用ParNew;
"-XX:ParallelGCThreads":指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同;
3.Parllel Scavenge收集器
由于关系吞吐量,所以Parllel Scavenge 收集器也成为“吞吐量优先”收集器。
Parallel Scavenge收集器也是一个新生代收集器,采用复制算法。也是多线程收集器。Parllel Scavenage 收集器与ParNew收集器的区别也是它的关注点,Parllel Scavenge追求可控的吞吐量。(CMS收集器关注的是尽可能缩短垃圾收集时用户线程的停顿时间。)高吞吐量可以高效的利用CPU时间,尽快完成程序的运算任务。(吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间))。
Parllel Scavenge收集器特点:
- 多线程
- 复制算法
- 年轻带
Parallel Scavenge 提供两个参数控制吞吐量:
- -XX:MaxGCPauseMills : 控制最大垃圾收集停顿时间。
- -XX:GCTimeRatio :设置吞吐量大小。
4.Serial Old收集器
Serial Old是Serial收集器的老年代版本。和Serial收集器一样是单线程收集器,使用“标记-整理”算法。Serial Old收集器也是Client模式下使用。
Serial Old收集器特点说明:
- 单线程
- 标记-清理算法
- 老年代
Serial Old收集器运行示意图:
5.Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本。使用多线程和“标记-清理”算法。JDK1.6版本提供。
Parallel Old收集器特点:
- 老年代
- 多线程
- 标记-清理算法
Parallel Old收集器运行示意图:
6.CMS收集器(Concurrent Mark Sweep)
CMS收集器是一种以获得最短回收停顿时间为目标的收集器。CMS收集器是基于“标记-整理”算法的老年代收集器。
CMS收集器过程分为4个步骤:
- 初始标记 --Stop the world
- 并发标记
- 重新标记--Stop the world
- 并发清除
初始标记和重新标记仍然需要Stop the world。
初始标记只是标记一下GC Roots直接关联的对象。
并发标记进行GC Roots Tracing过程。
重新标记是为了修正并发标记期间因用户程序继续运行而导致的标记产生变动的那一部分对象的标记记录。
整个过程中并发标记和并发清除所需要时间比较长,而这两个线程都可以与用户程序并发执行。所以总体上来说,CMS收集器回收过程与用户线程一起并发执行的。
CMS收集器运行示意图:
CMS收集器的缺点:(一定要看)
- CMS收集器对CPU非常敏感:在并发标记和并发删除阶段,虽然回收线程可以和用户线程并行执行,但回收线程还是占用了CPU资源。导致用户线程执行变慢,降低了吞吐量。CMS默认启动的线程数量是(CPU数量+3)/4。当CPU数量为4个时,回收线程消耗的CPU资源不低于25%,而且CPU数量越少,回收线程占用的资源越大。
- CMS收集器无法处理浮动垃圾:CMS收集器在并发删除阶段,由于回收线程和用户线程并发执行。所以CMS无法收集这段时间用户线程产生的垃圾。这部分垃圾叫做“浮动垃圾”。
- CMS收集器会产生大量的碎片空间。CMS收集器是基于“标记-清理”算法的。前面介绍过“标记-清理”算法会产生大量的碎片空间。碎片空间过多会给大对象的分配带来很大麻烦。出现这样一个现象:老年代空间剩余很多,但是没有足够的整块空间分配给大对象。而不得不触发Full GC。为了解决这个问题,CMS收集器提供了+UseCMSCompactAtFullCollection,用于CMS顶不住要Full GC时,开启内存碎片的合并整理过程。-XX:CMSFullGCsBeforeCompaction,这个参数用于执行多少次不压缩的Full GC,跟着来一次带压缩的Full GC.
7.G1收集器
G1(Grabage-First)收集器是JDK1.7提供的。是一款面向服务端应用的垃圾收集器。HotSpot赋予它的使命是在未来能够替换掉CMS收集器。
G1收集器的特点:
1.并行与并发:G1收集器能够利用多CPU,多核的硬件环境,缩短Stop-the-world停顿的时间。其他收集器原本需要停顿的GC操作,G1收集器依然可以通过并发让用户程序执行。
2.分代收集:G1收集器不需要与其他收集器配合就可以管理整个堆空间。G1收集器中也有分代的概念。
3.空间整合:G1收集器是基于“标记-整理”算法的。这种算法不会产生碎片空间。
4.可预测停顿:G1收集器除了追求停顿时间短以外,还能建立可预测停顿时间模型。
使用G1收集器时,内存区域的划分和别的收集器不同,虽然G1收集器还有年轻代和老年代的概念。但是G1收集器是把内存划分为若干个大小相等的区域(Region)。
G1收集器根据不同区域里面垃圾堆积价值大小在后台维护一个优先列表。每次根据回收时间,回收价值最大的区域(Garbage-First),保证在一定的回收时间内尽提高回收效率。
G1收集器运行示意图:
G1收集器运行步骤:
- 初始标记 --Stop the world
- 并发标记 -- 并发执行
- 最终标记 -- Stop the world
- 筛选回收 -- 并发执行
1).初始标记只是标记一下与GC Roots直接关联的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建对象。
2).并发标记阶段是回收线程和用户线程并发执行,回收线程进行GC Roots Tracing阶段(可达性分析阶段)。这段时间需要的时间比较长,但是回收线程和用户线程并发执行。
3).最终标记阶段是修改并发阶段由于用户线程执行而导致的标记产生变动的那一部分记录。最终标记阶段需要stop the world。
4).筛选回收阶段首先会按照区域(Region)回收价值和回收成本进行排序,然后根须用户所期望的GC停顿时间制定回收计划。
以上是java虚拟机7个垃圾收集器的介绍。