深入JVM内核(四)垃圾回收器与GC参数

堆的回顾

很多垃圾回收算法,如CMS,使用的堆内存结构如下:
堆

新手代:一个Eden和两个survivor
老年代:old space
持久带:1.8之前的perm space
元空间:1.8之后的metaspace

注:这些space必须是地址连续的空间

串行(Serial)收集器

  • 单线程的收集器
  • 它进行收集时,必须暂停其它所有线程,直到它收集结束
  • 可能会产生较长的停顿
  • 参数:-XX:+UseSerialGC
  • 收集方式:
    • 新生代、老年代均是串行回收
    • 新生代采用复制算法
    • 老年代采用标记-整理算法

Serial/Serial Old收集器运行示意图

并行(ParNew)收集器

  • 多线程
  • 其实就是Serial收集器的多线程版本
  • 更加关注吞吐量
  • 收集方式:
    • 新生代采用复制算法
    • 老年代采用标记-整理算法
  • -XX:+UseParallelGC
    • 使用Parallel收集器 + 老年代串行
  • -XX:+UseParallelOldGC
    • 使用Parallel收集器 + 老年代并行
  • -XX:MaxGCPauseMills
    • 最大停顿时间,单位毫秒
    • GC尽力保证回收时间不超过设定值
  • -XX:GCTimeRatio
    • 0-100的取值范围
    • 垃圾收集时间占总时间的比
    • 默认99,即最大允许1%时间做GC

最后两个参数是矛盾的。因为停顿时间和吞吐量不可能同时调优

Paralle/Paralle Old收集器运行示意图

CMS(Concurrent Mark Sweep)收集器

  • Concurrent Mark Sweep即并发标记清理(与用户线程一起执行)
  • 以获取最短回收停顿时间为目标的收集器
  • 从名字上可以看出CMS收集器是基于标记清除算法实现的:
    • 初始标记(CMS initial mark)
      • Step the world
      • 根可以直接关联到的对象
      • 速度快
    • 并发标记(CMS concurrent mark)
      • 和用户线程一起
      • 主要标记过程,标记全部对象
    • 重新标记(CMS remark)
      • Step the world
      • 由于并发标记时,用户线程依然运行,因此在正式清理前,再做修正
    • 并发清除(CMS concurrent sweep)
      • 和用户线程一起
      • 基于标记结果,直接清理对象

CMS收集器运行示意图

缺点:

  • 会影响系统整体吞吐量和性能
    • 比如,在用户线程运行过程中,分一半线程去做GC,系统性能在GC阶段就会减半
  • 清理不彻底
    • 由于在清理阶段还运行着用户线程,会产生新的垃圾,无法清理
  • 无法处理浮动垃圾,可能出现concurrent mode failure导致另一次GC发生
  • 使用标记清除算法,会导致大量内存碎片

相关参数:

  • -XX:CMSInitiatingOccupancyFraction
    • 设置触发GC的阈值,默认是老年代使用了68%触发
  • -XX:+ UseCMSCompactAtFullCollection
    • Full GC后,进行一次整理
    • 整理过程是独占的,会引起停顿时间变长
  • -XX:+CMSFullGCsBeforeCompaction
    • 设置进行几次Full GC后,进行一次碎片整理
  • -XX:ParallelCMSThreads
    • 设定CMS的线程数量

G1收集器

todo


参考: