Serial 收集器
该收集器是最基础、历史最悠久的收集器,是一个单线程工作的收集器,是在客户端模式下的默认新生代垃圾收集器,并不是说他只会使用一个处理器或者一条收集线程去完成垃圾收集工作,侧重强调当它进行垃圾收集时,必须暂停其他所有工作线程,直至它收集结束。但是这里的 “Stop The World”这个矛盾的问题,我们也同样可以理解,如果你在值日生打扫班级卫生时,他们一边打扫,你同时把垃圾人道地上,我们可以理解这样的矛盾。
优点
简单高效(在单线程下相比较)额外内存消耗最小
不足之处
用户线程由于垃圾收集而导致的停顿需要进一步提升
ParNew 收集器
该收集器是Serial收集器的多线程并行版本,除了使用多条线程进行垃圾收集之外,其余行为完全包括了Serial收集器可用的所有控制参数。而有一点特别的是:目前只有这款垃圾收集器能够与CMS收集器配合工作。
优点
随着可以被使用的处理器核心数量的增加,ParNew收集器对于垃圾收集时系统资源的高效利用能够有一定的推动作用。当处理器核心比较多时,可以使用参数-XX:ParallelGCThreads参数来限制垃圾收集器的线程数。
Parallel Scavenge 收集器
该收集器是一款基于标记-复制算法实现、支持并行收集的多线程、面向新生代的垃圾收集器,也叫吞吐量优先收集器。
特点
该收集器的目标是让自己及进行垃圾回收时能够达到一个可控的吞吐量(处理器用于运行用户代码的时间与处理器总耗时的比值),它使用两个参数实现了精确控制吞吐量
1)-XX:MaxGCPauseMills 最大垃圾收集停顿时间(大于 0 的毫秒数)
2)-XX:GCTimeRatio 垃圾收集占总时间比率,吞吐量的倒数 (大于 0 小于 100 的整数)
亮点
垃圾收集的自适应调整策略:不同于ParNew收集器的一个重要特性,激活参数-XX:UseAdaptiveSizePolicy,就不用去人工指定新生代的大小(-Xmn)、Eden 与 Survivor 区的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)这些细节参数了。
Serial Old 收集器
该收集器是 Serial 收集器的老年代版本,使用标记-整理算法。
作用
1)在JDK 5之前能够与Parallel Scavenge收集器搭配使用
2)作为CMS收集器发生失败后的备选预案,在并发收集发生Concurrent Mode Failure时使用。
Parallel Old 收集器
该收集器是 Parallel Scavenge 收集器的老年代版本,使用标记-整理算法
作用
使得“吞吐量优先”得到了名副其实的搭配组合,在注重吞吐量或者处理器资源较为稀缺的场合,都可以优先考虑Perallel Scavenge 加 Parallel Old 收集的搭配组合。
CMS收集器
该收集器是一种给以获得最短回收停顿时间为目标的收集器。使用标记-清除算法
运行流程
1)初始标记
标记一下 GC Roots 能够关联到的对象,速度非常快。
2)并发标记
从 GC Roots 的直接关联对昂开始,进行遍历对象图的过程,过程虽然耗时长,但是不需要停顿用户线程,可以与垃圾收集线程一起并发执行。
3)重新标记
为了修正并发标记期间,因用户线程继续运行而导致标记产生变动的那一部分对象的标记记录(增量更新)
4)并发清除
清理删除掉标记阶段判断已经死亡的对象。
总体来看,CMS收集器在并发标记和并发清除阶段,还是和用户线程进行并发执行的,但是通过上面的图片中,我们还是可以清晰的看见,该收集器需要停顿的地方,也就是在初始标记和重新标记这两步化石需要“Stop The World”
缺陷
1)CMS收集器对处理器资源非常敏感。
虽然并发执行,能够加快垃圾收集的效率,但是在处理器的资源应用方面,他还是会占用一部分资源去执行垃圾收集线程,如果,处理器核心数量不足时,并发收集还是很大程度的应影响用户的程序运行。(解决方法是虚拟机推出了一种称为“增量式并发收集器”的CMS收集器变种)。
2)CMS收集器无法处理“浮动垃圾”
当程序运行时,自然会不断有新垃圾对象的产生,但是这种垃圾CMS收集器无法在当此收集中处理它们,只好留在下次再进行处理。为了解决这部分浮动垃圾的问题,CMS收集器碧血预留一部分空间共并发收集时的线程使用。当CMS运行期间的预留内存无法满足程序分配新对象时,就会出现一次并发失败,这时候只能冻结用户线程的执行,而使用Serial Old收集器对于老年代进行垃圾收集。
3)收集垃圾结束后,会遗留大部分空间碎片
空间碎片过多,就会给大对象的空间分配带来麻烦,无法找到能够存储该对象合适的内存空间,这样就会提前出发一次Full GC的情况。
G1 (Garbage First)收集器
该收集器开创了收集器面向局部收集的设计思想和基于 Region 的内存布局形式。
特点
1)G1收集器的 Mixed GC 模式
以往的收集器拦击收集的目标范围要么是新生代,要么是老年代,再要么就是整个 Java 堆。但是,G1 收集器跳出这个笼络,它可以面向堆内任意部分来构成一个回收集进行回收。
2)G1收集器的 Region 堆内存模式
首先要清楚一点,G1收集器也是遵循分代收集理论的,但是 G1 收集器不再坚持固定大小以及固定数量的分代收集区域,而是将连续的 Java 堆分为大小相等的独立区域——Region,每个Region中都会包含新生代,老年代。
G1收集器迟迟没有问世,是因为G1收集器有些关键问题需要妥善解决
1)跨 Region 引用问题
G1的记忆集在存储结构特点上,其实是一个哈希表。其中的 Key 指向的是其他 Region 的内存起始地址,value 则是一个集合,用于存放数据(卡表的索引号)。双向的卡表结构,不仅记忆了“谁指向我”,还记忆了“我指向谁”
2)保证收集线程与用户线程的巩固走互不干扰
在用户线程改变对象之间的引用关系时,我们要保证不能够打断原有的对象图结构,导致标记错误。在G1收集器中,采用原始快照的方式来避免这一问题。
3)如何建立可靠的停顿预测模型
G1收集器采用的是以衰减均值为理论基础来实现的,G1收集器会记录在垃圾收集过程中,每一个 Region 的回收耗时,每一个 Region 记忆集中的脏卡数量以及各种可以观测步骤花费的成本。
我们根据前面所说的内容,可以归纳总结出G1垃圾收集器的工作过程,其实整体过程和 CMS 收集器很类似,主要分为一下四步:
1、初始标记:这次从GC Roots 出发进行标记,找出可以直接关联到的对象,并修改该手机其特有的TAMS指针,方便用户线程并发执行时,能够找到可用的Region区域,进行对象分配。
2、并发标记:这一步从GC Roots对于堆中对象进行可达性标记,在对象扫描结束之后,重新处理SATB记录下的并发时有引用变动的对象。
3、最终标记:对用户线程进行简单的停顿,处理并发阶段阶段结束后遗留下来的少量的SATB记录。
4、筛选回收:对各个Region区域进行回收,这里可以将需要回收的Region区域进行整体回收,也就是构成一个回收集,将需要回收的那部分进行清除,然后将存活队形复制到空的Region中,将旧的region空间清除。该部分需要暂停用户线程的执行,由多条收集线程并行执行垃圾回收