jvm 05-JVM垃圾收集策略

Posted liangjingfu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jvm 05-JVM垃圾收集策略相关的知识,希望对你有一定的参考价值。

GC策略

  • 新生代GC策略:
    • 串行GC:Serial Copying
    • 并行回收GC:Parallel Scavenge
    • 并行GC:ParNew
  • 老年代GC策略:
    • 串行GC:Serial MSC
    • 并行GC:Parallel MSC
    • 并发GC:CMC

新生代GC策略

新生代--串行GC(Serial Copying)

  • 算法:复制清理算法
  • 操作步骤:
  1. 扫描新生代中所有存活的对象
  2. 使用Minor GC进行垃圾回收,同时将存活对象保存到S0 or S1区
  3. 在上一次Minor GC的基础上进行S0和S1区的角色交换
  4. 经历许多次Minor GC依然存活的对象晋升到老年代

新生代--并行回收GC(Parallel Scavenge)

  • 算法:复制清理算法
  • 操作步骤:
    • 在扫描和复制时均采用多线程方式处理
    • 在新生代使用并行GC处理的时候会产生有一个STW(stop The World pause)的暂停,该暂停主要是进行对象回收,期间其他的线程将被暂时性挂起。
    • 并行回收GC为空间较大的新生代回收提供许多优化
    • 在多CPU的机器上,其GC耗时会比串行方式短
    • 该方式适合多CPU、对暂停时间要求较短的应用

技术分享图片

新生代--并行GC(ParNew)

  • 算法:复制清理算法
  • 操作步骤:
    • 并行GC必须结合老年代CMS GC一起使用。
    • 因为在新生代如果发生了Minor GC时,老年代也需要使用CMS GC同时处理
    • CMS(Concurrent Mark-Sweep)是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器,主要针对要求服务器响应速度快的应用

老年代GC策略

老年代--串行GC(Serial MSC)

  • 算法:标记-清除-压缩(Mark-Sweep-Compact)
  • 特点:串行执行的过程中为单线程,需要暂停应用并耗时较长
  • 操作步骤:
  1. 扫描老年代中还存活的对象,并且对这些对象进行标记
  2. 遍历整个老年代内存空间,回收所有未标记的对象内存
  3. 将所有存活对象都集中在一端,而后将所有回收对象的内存空间变为一块连续的内存空间

老年代--并行GC(Parallel )

  • 算法:标记-压缩(Mark-Compact)
  • 特点:
    • 多线程同时进行垃圾回收可以缩短应用的暂停时间
    • 但是由于老年代的空间一般较大,在扫描和标记存活对象上还是需要花费较长的时间
  • 操作步骤:
  1. 将老年代内存空间按照线程个数划分为若干个子区域
  2. 多线程并行对各自子区域内的存活对象进行标记
  3. 多线程并行清除所有未标记的对象
  4. 多线程并行将多个存活对象整理在一起,并将所有回收的对象空间整合为一体

老年代--并发GC(Concurrent Makr-Sweep GC、CMS GC )

  • 算法:标记-清除(Mark-Sweep)
  • 特点:
    • 只有在第一次和重新标记阶段才会暂停整个应用,这样对应用程序所带来的影响非常小。
    • 并发标记与回收线程会与应用线程争抢CPU资源,并且容易产生内存碎片。
  • 操作步骤:
  1. 初始标记(STW Initial Mark):虚拟机暂停正在执行的任务(STW),由根对象扫描出所有的关联对象并做出标记。此过程只会导致短暂的JVM暂停。
  2. 并发标记(Concurrent Marking):恢复所有暂停的线程对象,并且对之前标记过的对象进行扫描,取得所有跟标记对象有关联的对象。
  3. 并发预清理(Concurrent Precleaning):查找所有在并发标记阶段新进入老年代的对象(可能是从新生代晋升到老年代或被分配到老年代),通过重新扫描,减少下一阶段的工作。
  4. 重新标记(STW Remark):此阶段会暂停虚拟机,对在并发标记阶段被改变引用或新创建的对象进行标记
  5. 并发清理(Concurrent Sweeping):恢复所有暂停的应用线程,对所有未标记的垃圾对象进行清理,并且尽量将已回收对象的空间重新拼凑为一个整体。在此阶段收集器线程和应用程序线程并发执行。
  6. 并发重置(Concurrent Reset):重置CMS收集器的数据结构,等待下一次垃圾回收。

技术分享图片

GC参数

GC策略调整参数

  • -XX:+UseSerialGC -- Serial Copying + Serial MSC
  • -XX:+UseParallelGC -- Parallel Scavenge + Parallel Mark Sweep
  • -XX:+UseConcMarkSweepGC -- ParNew + Concurrent Mark-Sweep GC
  • -XX:+UseParNewGC -- ParNew + Serial MSC
  • -XX:+UseParallelOldGC -- Parallel Scavenge + Parallel Mark Sweep

收集参数设置

  • -XX:ParallelGCThreads=n:设置并行收集器操作使用的CPU数量
  • -XX:MaxGCPauseMillis=n:设置并行收集器的最大暂停时间,单位为毫秒
  • -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比
  • -XX:+CMSIncrementalMode:设置增量模式,适合单CPU模式。需要使用-XX:+UseConcMarkSweepGC策略

测试代码:

package cn.liang.jvm;
public class gctest2 {
  public static void main(String[] args) {
      String string = "liang";
      while (true) {
          string += string + string;
          string.intern();    
      }
  }
}

默认的GC策略:Parallel Scavenge + Parallel MSC

-Xmx10m -Xms10m -XX:+PrintGCDetails
输出结果:
[Full GC (Allocation Failure) 
[PSYoungGen: 0K->0K(1536K)] 
[ParOldGen: 4082K->4070K(7168K)] 4082K->4070K(8704K), 
[Metaspace: 2649K->2649K(1056768K)], 0.0047164 secs] 
[Times: user=0.00 sys=0.00, real=0.01 secs]

使用串行GC策略:Serial Copying + Serial MSC

-Xmx10m -Xms10m -XX:+UseSerialGC -XX:+PrintGCDetails
输出结果:
[GC (Allocation Failure) 
[DefNew: 2581K->2581K(3072K), 0.0000758 secs]
[Tenured: 5989K->4084K(6848K), 0.0034008 secs] 8570K->4084K(9920K), 
[Metaspace: 2649K->2649K(1056768K)], 0.0035313 secs] 
[Times: user=0.00 sys=0.00, real=0.01 secs]

使用并行GC策略:Parallel Scavenge + Parallel Mark Sweep

-Xmx10m -Xms10m -XX:+UseParallelGC -XX:+PrintGCDetails
输出结果:
[Full GC (Allocation Failure) 
[PSYoungGen: 224K->0K(2560K)] 
[ParOldGen: 5347K->2816K(7168K)] 5571K->2816K(9728K), 
[Metaspace: 2648K->2648K(1056768K)], 0.0039458 secs] 
[Times: user=0.01 sys=0.00, real=0.01 secs]

使用CMS回收:ParNew + Concurrent Mark-Sweep GC

  • 这对整个程序的暂停时间会非常短暂,适合于响应速度快的程序
-Xmx10m -Xms10m -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails
输出结果:
[GC (Allocation Failure) 
[ParNew: 2584K->2584K(3072K), 0.0000325 secs]
[CMS (concurrent mode failure): 4941K->4087K(6848K), 0.0030993 secs] 7526K->4087K(9920K), 
[Metaspace: 2649K->2649K(1056768K)], 0.0032009 secs] 
[Times: user=0.00 sys=0.00, real=0.00 secs]

总结:

  • 如果程序没有对运行速度要求的话,建议使用默认的GC策略
  • 所有的GC策略都有一个问题:都需要扫描全部子内存

以上是关于jvm 05-JVM垃圾收集策略的主要内容,如果未能解决你的问题,请参考以下文章

JVM垃圾收集器和收集器的选择策略

jvm系列 ---垃圾收集器与内存分配策略

深入理解JVM——垃圾收集策略具体解释

深入了解JVM——垃圾收集器与内存分配策略

JVM之垃圾收集器 (GC) 与内存分配策略

jvm系列jvm垃圾收集器与内存分配策略