JVM学习笔记——垃圾收集器

##垃圾收集器
垃圾收集器内容颇多,但算法原理都是基于垃圾收集算法,故这里只简单介绍一下各收集器的特点。

  • HopSpot中的收集器群


    两个虚拟机之间的连线表示它们可以搭配使用,反之则不能搭配。

  • Serial收集器

    Serial&Serial Old
    • 使用“标记-整理”算法
    • “单线程”收集器,这里的单线程指的是Serial在对某一条线程执行收集工作时,必须暂停其他线程的运行,这就会造成大量的GC停顿出现。
    • 优点是简单高效,在Client模式的虚拟机中表现优秀。

  • Serial Old收集器

    • Serial的老年代版本,特性基本与Serial一致。
    • 在JDK1.5之前可以与Parallel搭配使用,或者作为CMS的后备方案。

  • ParNew收集器

    • ParNew就是针对Serial改进的多线程版本。
    • 在很多虚拟机中,ParNew却是新生代的首选收集器,因为除了Serial只有它能够与CMS搭配使用。

  • Parallel Scavenge收集器

    Parallel Scavenge&Parallel Old
    • 是一个新生代的收集器,使用多线程+复制算法。
    • 主要关注吞吐量的收集器吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),提供两个参数用于精确控制吞吐量:
      • -XX:MaxGCPauseMillis,最大GC停顿时间。允许的值是一个大于0的毫秒数,收集器尽可能保证收集时间不超过该值。注意,停顿时间缩短需要牺牲吞吐量和空间,更小的停顿时间可能会导致更频繁的GC。
      • -XX:GCTimeRatio,GC时间占总时间比率。是一个0-100之间的整数,等于吞吐量的倒数。

  • Parallel Old收集器

    • Parallel Scavenge的老年代版本,使用多线程+标记整理算法。
    • 由于Serial Old在服务端上性能不佳,故有了该收集器与Parallel Scavenge进行搭配使用。

  • CMS收集器(Concurrent Mark Sweep)

    • 基于标记-清除算法实现,是一款以获取最短GC停顿时间为目标的收集器。它的运作过程分为4步:

      • 初始标记
        标记GC Roots能关联到的对象。
      • 并发标记
        由GC Roots发起对象的跟踪,验证是否可达。
      • 重新标记
        修正并发标记期间变动的一部分对象的标记记录。
      • 并发清除
        清除标记对象的空间。

      其中只有初始标记与重新标记两个过程需要进行停顿,但是这两个过程仅仅是标记,速度很快,最漫长的清除过程在CMS下可以与用户线程并行处理。

    • CMS虽然很强大,但还是有着以下3个缺点:
      • 虽然CMS不会导致GC停顿,但并发的代价就是会占用CPU资源,可能会导致用户程序变慢,在核数较低的CPU中该问题会越发明显。
      • 由于CMS的清理不会暂停用户线程,可能导致“浮动垃圾”的出现,那就需要留出一部分内存空间对应“浮动垃圾”,所以CMS有一个触发回收的内存比例,在JDK1.6中该值默认为92%。如果预留的内存还是无法满足程序需求,CMS就会启动备用方案(一般是Serial Old)来重新进行收集。
      • 由于CMS使用的是标记-清除算法,所以会有大量的内存碎片产生,会导致大对象找不到空间存放而提前触发一次Full GC进行内存整理。
  • G1收集器

    在JDK1.7之后才出现的收集器,G1具备以下四个特点:
    • 并行与并发,能利用多线程,多CPU的优势,使得GC与用户线程并行。
    • G1能够独自对整个GC堆进行管理,并且留有了分代的特性,可以根据不同的区域采用不同的方式处理。
    • 将Java堆划分为多个大小相等的独立区域(Region),在Region上来看是基于复制算法实现的,从整体上看是基于标记-整理算法实现,结合了两种算法的优点。
    • 建立了可预测的停顿模型,可以通过-XX:MaxGCPauseMillis来设置期望GC时间,G1会尽量在该时间内完成GC。