Serial收集器
Serial收集器是最基础,历史最悠久的收集器,在jdk1.3.1之前是HotSpot的新生代收集器的唯一选择,大家只看名字就能够猜到,这个收集器是一个单线程的收集器,它的“单线程”的意义不仅仅是说明它只会使用一个处理器或者一条手机线程去玩完成垃圾收集工作,更重要的是签掉它在垃圾收集时必须暂停其他的所有工作线程,知道它收集结束。Stop The World 这个词语也许听起来很酷 但是这项工作是由虚拟机在后台发起和自动完成的,用户不可知不可控的状态下把用户正常工作的线程全部停止掉
这对于很多应用来说都是不可以接受的
CMS收集器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java用用集中在互联网网站或者基于留恋其的BS系统的服务端上,这类应用最关注服务的相应速度,系统系统停顿的时间尽可能的短,以给用户良好的交互体验,CMS就非常符合这类应用的需求
CMS—Concurrent Mark Sweep 从名字上面就可以看出来这种收集器的实现算法的基于
标记-清除算法实现的 整个运作过程分为四个步骤,包括:
- 初始标记(CMS initial mark)
- 并发标记(CMS concurrent mark)
- 重新标记(CMS remark)
- 并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤仍然需要 stop the world 初始标记仅仅是标记一下GC ROOTS能够直接关联到的对象,速度很快,并发标记阶段就是从GCRoots的直接关联对象开始遍历整个对象图的过程,整个过程耗时较长,但是不需要停顿用户线程,可以与垃圾收集器线程一起并发运行;而重新标记阶段则是为了修正并发标记期间,由于用户程序继续运作而导致标记变动的那一部分对象的标记记录 这个部分的时间会比初始标记的时间稍微长一点,但是也是远远低于并发标记的时间,最后是并发清除阶段,由于不需要移动存活的对象,所以这个阶段也是可以和用户线程并发的
CMS收集器的缺点:
-
对处理器资源非常敏感
事实上,面向并发设计的程序都对处理器资源比较敏 感。在并发阶段,它虽然不会导致用户线程停顿,但却会因为占用了一部分线程(或者说处理器的计 算能力)而导致应用程序变慢,降低总吞吐量。
-
CMS收集器无法处理“浮动垃圾”(Floating Garbage)
在CMS的并发标记和并发清理阶 段,用户线程是还在继续运行的,程序在运行自然就还会伴随有新的垃圾对象不断产生,但这一部分 垃圾对象是出现在标记过程结束以后,CMS无法在当次收集中处理掉它们,只好留待下一次垃圾收集 时再清理掉。这一部分垃圾就称为“浮动垃圾”。
-
产生空间碎片
CMS是一款基于“标记-清除”算法实现的收集器,如果 读者对前面这部分介绍还有印象的话,就可能想到这意味着收集结束时会有大量空间碎片产生。空间 碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很多剩余空间,但就是无法找 到足够大的连续空间来分配当前对象,而不得不提前触发一次Full GC的情况。
Garbage First收集器(G1收集器)
采用Mixed GC
在G1收集器出现之前的所有 其他收集器,包括CMS在内,垃圾收集的目标范围要么是整个新生代(Minor GC),要么就是整个老 年代(Major GC),再要么就是整个Java堆(Full GC)。而G1跳出了这个樊笼,,它可以面向堆内存任 何部分来组成回收集(Collection Set,一般简称CSet)进行回收,衡量标准不再是它属于哪个分代,而 是哪块内存中存放的垃圾数量最多,回收收益最大,
Region
G1开创的基于Region的堆内存布局是它能够实现这个目标的关键,G1不再坚持固定大小以及固定数量的 分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region)每一个Region都可以 根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。
Humongous
Region中还有一类特殊的Humongous区域,专门用来存储大对象。
G1的大多数行为都把Humongous Region作为老年代 的一部分来进行看待
G1相对于CMS的优势
-
可以指定最大停顿时间
-
分Region的内存布局
-
按收益动 态确定回收集
-
算法更优
与CMS 的“标记-清除”算法不同,G1从整体来看是基于“标记-整理”算法实现的收集器,但从局部(两个Region 之间)上看又是基于“标记-复制”算法实现,无论如何,这两种算法都意味着G1运作期间不会产生内存 空间碎片,垃圾收集完成之后能提供规整的可用内存,这种特性有利于程序长时间运行,在程序为大 对象分配内存时不容易因无法找到连续内存空间而提前触发下一次收集。
G1相对于CMS的劣势
-
内存占用更高
主要由于跨代收集的时候每个region都要单独维护卡表
-
执行负载高