关闭

垃圾收集器介绍

标签: 虚拟机
217人阅读 评论(0) 收藏 举报

1.Serial收集器

Serial是最基本历史最悠久的收集器,曾经(在JDK1.3.1之前)是虚拟机新生代收集的唯一选择。它是单线程收集器。单线程的含义是指他只会使用一个CPU或者一条收集线程来完成收集工作,而且在它进行收集的时候,必须暂停其他所有的工作线程。虽说Serial收集器对于商业的大型虚拟机不适用,但是确实Client模式下默认的新生代收集器。因为它简单高效。同时桌面端的新生代不会太大,回收也比较快,停顿时间一般很小,在可接受范围之内。

2.ParNew收集器

它是Serial收集器的多线程版本,它是多线程收集垃圾的。除了Serial收集器外,目前只有它可以和CMS收集器配合工作。当CPU非常多时,它对于GC时系统资源的有效利用还是很好的。它也是暂停所有的应用线程来进行垃圾回收。Serial收集器和 ParNew收集器都是带有整理Compact过程的收集器,采用指针碰撞的方法分配对象内存。

3.Parallel Scavenge收集器

这是一个新生代收集器,使用复制算法,并行的多线程收集器。CMS等收集器关注与尽可能地缩短垃圾收集时用户线程的停顿时间;而Parallel Scavenge收集器致力于达到一个可控制的吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

4.Serial Old收集器

Serial收集器的老年代版本,使用标记-整理算法,也是给Client模式下的虚拟机使用。现在主要用途是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。

5.Parallel Scavenge收集器收集器的老年代版本,使用多线程和标记-整理的算法。在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge和Parallel Old收集器。

6.CMS收集器
CMS收集器关注与尽可能地缩短垃圾收集时用户线程的停顿时间。基于标记-清除的算法,运行过程分为4个过程,初始标记和重新标记仍然会停掉所有工作线程。并发收集、低停顿的收集器

  • 初始标记:标记GC Roots能直接关联到的对象,速度很快
    并发标记:进行GC Roots Tracing的过程
    重新标记:修正并发标记期间因用户程序继续运作而导致标记发生变动的那一部分对象的标记记录,停顿时间比初始标记长,远比并发标记短。
    并发清除:并发标记和并发清除都是可以和用户线程一起工作。CMS有以下三个缺点:

  • 对CPU资源敏感。面向并发设计的程序一般都对CPU资源敏感。在并发阶段,随便它不会导致用户线程停顿,但是会占用一部分CPU资源,导致应用程序变慢,总吞吐量降低。

  • 无法处理浮动垃圾。可能出现”Concurrent Mode Failure“失败导致另外一次Full GC。由于CMS并发清理阶段用户线程还在运行,伴随程序运行自然产生了新的垃圾,CMS无法在当次收集中处理掉他们,只能留作下一次GC清理。这部分垃圾就是浮动垃圾。由于在垃圾收集阶段用户线程还需要运行,因此需要预留足够的内存给用户线程使用。所以CMS不能像其他老年代收集器一样等老年代几乎填满再进行收集。要是CMS在运行时预留的内存(在JDK1.6中,CMS启动阈值为92%)无法满足程序需要,就会出现”Concurrent Mode Failure“失败,这是虚拟机启动后备预案:临时启用Serial Old收集器来重新进行老年代垃圾收集,这样停顿时间就长了。
  • 由于CMS采用标记-清除算法,因此它会产生大量的空间碎片。空间碎片过多时,就给大对象分配空间带来了很大的麻烦。如果无法找到足够大的空间来分配当前对象,就会提前进行Full GC。CMS设置-XX:+UseCMSCompactAtFullCollection(默认开启)会在顶不住进行Full GC时开启内存碎片的合并整理过程,这是无法并发的,空间碎片没了,停顿时间就长了。此外设置-XX:CMSFullGCsBeforeCompaction,可以设置进行多少次Full GC之后来一次压缩的Full GC。

7.G1收集器
G1是一款面向服务端应用的垃圾收集器。G1有以下特点:

  • 并行与并发:G1能利用多CPU的优势来缩短停止用户线程的时间,也可以在GC时让用户线程继续执行
  • 分代收集:能够采用不同的方式来处理新创建的对象和已经存货一段时间的对象
  • 空间整合:G1从整体上采用标记-整理算法,从局部上是基于复制算法,不会产生内存碎片
  • 可预测的停顿:G1和CMS都追求低停顿时间,除此之外,G1还能建立可预测的停顿时间模型

使用G1收集器时,Java堆的内存格局划分为多个大小相等的独立区域(Region),新生代老年代不是物理隔离的,它们都是一部分区域的集合。G1通过追踪各个区域的垃圾堆积的价值大小(回收所获得的空间大小和所花费的时间),在后台维护一个优先列表,每次根据允许的收集时间,优先收回价值最大的区域(Garbage-First由来),这个方法保证了G1的回收效率。

存在的问题:一个对象分配在某个Region,并非只被本Region的对象引用,还可能和其他Region有引用关系,在做可达性分析时,可能需要扫描整个Java堆。 解决办法:虚拟机通过使用Remembered Set来避免全堆扫描,每一个Region对应一个Remembered Set,虚拟机发现程序对引用类型进行写操作时,产生一个Write Barrier中断写操作,检查引用的对象是否处于不同的Region之中,如果是,便通过CardTable把相关的引用信息记录到被引用对象的Region的Remembered Set中,内存回收时,通过在GC根节点的枚举范围加入Remembered Set可保证不对全堆进行扫描
G1收集器运作的步骤:

  • 初始标记:标记GC Roots能直接关联到的对象,速度很快(同CMS)
  • 并发标记:进行GC Roots Tracing的过程(同CMS)
  • 最终标记:修正并发标记期间因用户程序继续运作而导致标记发生变动的那一部分对象的标记记录,对象变化记录存在线程Remembered Set Logs,最终标记就是把Remembered Set Logs数据合并到Remembered Set中。可以和用户线程并发执行
  • 筛选标记:对各个Region回收价值和成本进行排序,根据用户所期望的GC停顿时间制定回收计划。可以和用户线程并发执行
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:12264次
    • 积分:522
    • 等级:
    • 排名:千里之外
    • 原创:39篇
    • 转载:5篇
    • 译文:0篇
    • 评论:0条