Hotspot VM的实现

  1. OopMap:在类加载完成后记录下对象内的数据类型与偏移量,在JIT编译过程中记录下栈和寄存器中哪些位置是引用。
  2. 安全点:在指令序列复用时,如方法调用,循环跳转,异常跳转等。
  3. 中断:

    • 抢先式中断:不需要线程代码配合,当GC发生时,先把所有线程都中断,如果发现线程中断的点不在安全点上,则恢复线程,让他跑到安全点上。
    • 主动式中断:当GC需要中断线程的时候,在安全点上设置中断标志,线程执行时主动轮询中断标志,发现标志为真时则主动中断挂起线程。
  4. 安全区域:指线程在某一段代码片段中,引用关系不会发生变化,在这个区域中的任意点开始GC都是安全的。在线程处于blocked或sleep状态无法跑到安全点时,采用安全区域可以避免GC长时间等待。

垃圾收集器

  1. Serial收集器:单线程,进行垃圾收集时必须暂停所有工作线程。Client模式下默认新生代收集器。采用复制算法。优点:简单高效,进行垃圾收集时不需要与工作线程交互。缺点:必须暂停所有工作线程,停顿时间较长。
  2. Serial Old收集器:Serial收集器的老年代版本。主要也是在Client模式下使用,在Server模式下,主要与Parallel Scavenge收集器搭配使用,或作为CMS收集器的后备预案。采用标记-整理算法。
    Serial / Serial Old 收集器运行示意图
  3. ParNew收集器:Serial收集器的多线程版本,除了能够多线程进行垃圾收集以外,其他与Serial收集器相似,进行垃圾收集时必须暂停所有工作线程。Server模式下默认新生代收集器。采用复制算法。在CPU核心数量较多的时候垃圾收集效率较高,但在CPU核心数量较少的时候效率不一定比Serial收集器高。
    ParNew / Serial Old 收集器运行示意图
  4. Parallel Scavenge收集器:与ParNew类似,也是多线程收集器,但更关注于达到一个可控制的吞吐量(用于执行用户代码的CPU时间与CPU总消耗时间的比值)。采用复制算法。
  5. Parallel Old收集器:Parallel Scavenge的老年代版本。采用标记-整理算法。
    Parallel Scavenge / Parallel Old 收集器运行示意图
  6. CMS收集器:并发收集器,追求最短回收停顿时间,适合追求服务响应速度的服务端应用。采用标记-清除算法。优点:收集过程中耗时最长的步骤都可以和用户工作线程并发工作。缺点:对CPU资源非常敏感,在CPU核心数较少的情况下,对应用的运行速度有较大影响;无法处理浮动垃圾,即在垃圾收集过程中总有新的垃圾不断产生,只能积累到下一次GC再收集;标记-清除算法容易导致产生大量内存碎片,从而提前触发Full GC。
    CMS 收集器运行示意图
  7. G1收集器:并行与并发;分代收集;空间整合;可预测的停顿。使用Region划分GC堆。
    G1 收集器运行示意

并行收集器与并发收集器

  • 并行(Parallel)收集器:指多条垃圾收集线程并行工作,但此时用户工作线程仍然处于等待状态。
  • 并发(Concurrent)收集器:指用户工作线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户工作线程在继续执行,而垃圾收集程序运行与另一个CPU上。

内存分配与回收策略

  1. 对象优先在Eden分配:当Eden区空间不足时,将触发Minor GC。
  2. 大对象直接进入老年代
  3. 长期存活的对象将进入老年代:当对象的年龄增加到一定程度时(默认为15),它将会被移动到老年代中。

    • 对象的年龄:对象出生并且经过第一次Minor GC后仍然存活并且能被Survivor容纳的话,将被移动到Survivor空间中,并且年龄记为1,在Survivor空间中每经历一次Minor GC,对象的年龄就增加1。
  4. 动态年龄判定:如果Survivor空间中相同年龄的对象大小总和大于Survivor空间的一半,则年龄大于或等于该年龄的对象就可以直接进入老年代。
  5. 空间分配担保:新生代采用的是复制收集算法,Eden和Survivor始终只是用其中一块内存区,当出现Minor GC后大部分对象仍然存活的话,就需要老年代进行分配担保,把Survivor区无法容纳的对象直接晋升到老年代。

    • Minor GC是否安全:在进行Minor GC之前,虚拟机会先检查老年代的最大可用连续空间是否大于新生代所有对象总空间,如果大于,则此次Minor GC是安全的;否则则要检查HandlePromotionFailure参数是否允许担保失败,如果允许,则会继续检查老年代的最大可用连续空间是否大于历次进入老年代的对象的平均大小,如果大于,则尝试进行一次Minor GC;如果小于,或者不允许担保失败,则进行一次Full GC;如果尝试进行的Minor GC失败了,也要进行一次Full GC。

新生代GC与老年代GC

  • 新生代GC(Minor GC / Young GC):指发生在新生代的垃圾收集动作,Minor GC非常频繁,速度也比较快。
  • 老年代GC(Major GC / Full GC):指发生在老年代的垃圾收集动作,出现了Major GC,经常会伴随至少一次Minor GC。Major GC的速度一般会比Minor GC慢10倍以上。