Java - GC Collector (垃圾回收器)

163 阅读4分钟

1. Serial

  新生代收集器,单线程回收。有点在于简单而有效,对于运行在Client模式下的虚拟机是很好的选择(用户桌面应用)。
  参数 -XX:UseSerialGC ,打开此开关后,使用 Serial + Serial Old 的收集组合进行内存回收。

2. ParNew

  新生代收集器,Serial的多线程版本,除了Serial收集器之外,只有它能与CMS收集器配合工作。
  -XX:+UseConcomarkSweepGC 选项后默认的新生代收集器,也可以使用 -XX:+UseParNewGC 选项来强制指定它。
  ParNew 收集器在单CPU的环境中,效果不如Serial好,随着CPU的增加,对于GC时系统资源的利用还是有效的。
  默认开启的收集线程数和CPU数相等,可以使用 -XX:ParallerlGCThreads 指定。

3. Parallel Scavenge

  新生代收集器,并行收集器,复制算法,和其他收集器不同,关注点的是吞吐量(垃圾回收时间占总时间的比例)。提供了两个参数用于控制吞吐量。
  -XX:MaxGCPauseMillis 最大垃圾收集停顿时间,减少GC的停顿时间是以牺牲吞吐量和新生代空间来换取的,不是设置的越小越好。
  -XX:GCTimeRatio 设置吞吐量大小,值大于0小于100的范围,相当于吞吐量的倒数,比如设置成99,吞吐量为:1/(1+99)=1%。
  -XX:UseAdaptiveSizePolicy 开关参数。打开之后不需要设置新生代大小 -Xmm  Eden **** Survival 的比例 -XX:SurvivalRatio 、晋升老年大对象年龄 -XX:PretenureSizeThreshold 等细节参数,收集器会自动调节这些参数

4. Serial Old

  是 Parallel Scavenge 的老年代版本。在注重吞吐量的场合,都可以优先考虑 Parallel ScavengeParallel Old 配合使用。

5. CMS

  Concurrent Mark Sweep 是一种以获取最短回收停顿时间为目标的收集器,尤其重视服务的响应速度。基于标记-清除算法实现。
  分为四个步骤进行垃圾回收:初始标记并发标记并发清除。只有初始标记和重新标记需要停顿。
  初始标记只是标记一下GC Roots能直接关联到的对象,速度快。并发标记就是进行GC Roots的Tracing。
  重新标记为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间会比初始标记阶段长,远比并发时间短。
  好使最长的并发标记和并发清除过程中,处理器可以与用户线程一起工作。

缺点

  1. 垃圾回收时会占用一部分线程,系统变慢,总吞吐量会降低。
  2. 无法处理浮动垃圾,需要预留足够的内存空间给用户线程使用,可以通过 `-XX:CMSInitiatingOccupancyFraction 参数控制触发垃圾回收的阈值。
  3. 如果预留的内存无法满足程序需要,出现Concurrent Mode Failure失败,这是将启动应急预案,启用Serial Old进行垃圾回收,停顿时间会变长
  4. -XX:CMSInitiatingOccupancyFraction 参数的值设置的太高,导致频繁Concurrent Mode Failure失败,性能降低。
  5. 标记清理容易产生碎片。 -XX:UseCMSCompactAtFullCollection 开启碎片整理功能,默认开启, -XX:CMSFullGCBeforeCompaction ,控制多少次不压缩的FullGC之后来一次带压缩的。

6. G1

  包括新生代和老年代的垃圾回收。和其他收集器相比的优点:并行和并发,分代收集,标记-整理,可预测的停顿。垃圾回收分为以下几个步骤:

  • 初始标记:标记GC Roots能够直接关联的对象,这阶段需要停顿线程,时间很短。
  • 并发标记:进行可达性分析,这阶段耗时比较长,可与用户程序并发执行。
  • 最终标记:修正发生变化的记录,需要停顿线程,但是可并行执行。
  • 筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来执行回收计划。

canvas.png