`

JVM GC总结

阅读更多

JVM GC总结

 

参考 林昊 <分布式Java应用基础与实践>

 

1. 首先需要弄清JVM的内存结构,参考: 【转】JVM内存结构  

 

2. JVM GC 大致可分为三类:Minor GC,Major GC和Full GC.

 

   Minor GC指堆内存 新生代上发生的垃圾回收.

   

   Major GC是指堆内存的旧生代 和 非堆内存的持久代 上发生的垃圾回收.

   

   因为通常发生Major GC时至少要进行一次的Minor GC,

   所以将这种Minor GC和Major GC同时发生的GC称为Full GC.

   需要注意的是,并不是所有的Major都会导致Full GC.

   (比如,在 ParallelScavenge 收集器的收集策略里,就有直接进行 Major GC 的策略选择过程)

   通常可以任务发生Major GC时就是发生Full GC之时.

   

3 Minor GC 和 Major GC 都有几种不同的方式可选择.

 

3.1 新生代可用的GC(Minor Gc)

 

    Minor GC 采用复制算法,将存活的对象从Eden和S0(或S1)拷贝到S1(或S0)上.

 

3.1.1 串行GC(Serial GC)

   

      对象在从存活区(S0或S1)拷贝到旧生代之前经历的Minor次数由-XX:MaxTenuringThreshold控制

      

      Eden 和 Survivor的空间大小受参数:-XX:SurvivorRatio控制.

      SurvivorRatio = Eden 空间 / 一个Survivor的空间

      比如新生代-Xmn10M,-XX:SurvivorRatio = 8,则Eden为8M,每个Survivor为1M.

      

      通过配置JVM参数:-XX:PretenureSizeThreshold

      使得对象大小超过这个数值时,对象直接在旧生代上分配空间.

      

      Serial GC 在整个扫描和复制过程中都采用单线程的方式来进行,更加适用于单CPU,新生代空间较小,

      以及对暂停时间要求不是非常高的应用.是client级别(CPU核数小于2或物理内存小于2GB)或32位

      windows机器上默认的GC方式.

      

      使用,-XX:+UseSerialGC参数强制使用Serial GC.

  

3.1.2 并行回收GC(Parallel Scavenge)

      

      Eden S0 S1大小受InitialSurvivorRatio控制,JDK1.6之后也可以通过SurvivorRatio,但并行回收GC

      将此值+2然后赋给InitialSurvivorRatio.

      (1) InitialSurvivorRatio 和 SurvivorRatio都不设置

          用-Xms20m -Xmx20m -Xmn10m -XX:+UseParallelGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGC

          执行,则Eden为7.5M,S0和S1 为1.25M,则7.5/1.25 = 6.

      (2) 只配置SurvivorRatio = 10

          用-Xms20m -Xmx20m -Xmn12m -XX:+UseParallelGC -XX:SurvivorRatio=10 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGC

          此时 Eden =10M,S0和S1 为1M,则10 / 1 = 10 等于设置的-XX:SurvivorRatio=10

      (3) 只设置 InitialSurvivorRatio = 10

          用-Xms20m -Xmx20m -Xmn10m -XX:+UseParallelGC -XX:InitialSurvivorRatio=10 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGC

          此时Eden =8M,S0和S1 为1M,8 / 1 = 8 = InitialSurvivorRatio - 2

      (4) 同时设置SurvivorRatio = 10 和 InitialSurvivorRatio = 10

          用-Xms20m -Xmx20m -Xmn10m -XX:+UseParallelGC -XX:SurvivorRatio=10 -XX:InitialSurvivorRatio=10 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGC

      因此,采用并行回收GC时: 

      如果没有配置SurvivorRatio和InitialSurvivorRatio,则默认值,Eden / Survivor = 6; 

      如果只配置了SurvivorRatio = 10则以这个为准Eden / Survivor = SurvivorRatio ;

      如果只配置了InitialSurvivorRatio = 10 则 Eden / Survivor = InitialSurvivorRatio - 2;

      如果同时配置了InitialSurvivorRatio 和 SurvivorRatio,则以InitialSurvivorRatio 为准,Eden / Survivor = InitialSurvivorRatio - 2

      另外,使用并行回收GC时,虚拟机会根据运行情况动态调整Eden S0 和S1的大小,上面的值只是设置初始值,

      可用通过使用-XX:-UseAdaptiveSizePolicy固定Eden S0和S1的大小为上面设置的值.

      

      对于对象是否直接在旧生代上分配不受-XX:PretenureSizeThreshold控制,而是在Eden空间不够情况下,

      当对象大小大于等于Eden大小一半时,即在旧生代上分配.

      

      并行回收GC(Parallel Scavenge)也是采用复制算法,但是在扫描和复制是均采用多线程方式,且并行回收GC为大的

      新生代回收做了很多优化.在多CPU机器上其回收的耗时比串行方式短,适用于多CPU,对暂停时间要求短的应用上.

      并行回收GC是server级别(CPU核数超过2且物理内存超过2GB)的机器(32位window除外)上默认的GC方式.并行线程数量

      在CPU核数小于等于8时,即为CPU核数,当CPU核数多于8时,计算公式为:3 + (CPU核数 * 5) / 8,也可通过

      -XX:ParallelGCThreads = 4 来强制制定.

      

      使用-XX:+UseParallelGC强制使用并行回收GC(Parallel Scavenge)

 

3.1.3并行GC(ParNew)

  

     Eden 和S0 S1的空间分配方式和串行GC采用的方式相同.

     

     并行GC方式必须与旧生代的CMS GC方式配合使用. CMS GC方式要求 Minor GC需采用并行方式并做一些特殊处理

     (并行回收方式没有这种特殊处理),因此CMS GC只能和 并行GC(ParNew)一同使用.

     同时,也是因为并行GC(ParNew)的特殊处理,是的Major GC的并行回收方式不能和ParNew GC方式同时使用.

     

     使用-XX:+UsePaNewGC强制使用并行GC(ParNew)

 

3.2 旧生代和持久代可用的GC

    

    JDK提供了串行,并行及并发三种GC来对就生代及持久代对象所占用的内存进行回收.

    

3.2.1 串行GC

 

     串行基于Mark - Sweep - Compact实现,结合了Mark - Sweep, Mark - Compact做了一些改进.

     过程:

     (1) 从根集合对象扫描,按照三色着色啊法哪个是对对象进行标识;

     (2) 遍历旧生代或持久代,找出未标记对象,并回收其内存;

     (3) 执行活动压缩(Sliding Compaction)

     

     串行执行过程中需要暂停应用.采用单线程方式,通常需要耗费较长时间,通过

     -XX:+PrintGCApplicationStopTime来查看GC造成的暂停时间.

     

     通过-XX:+UseSerialGC强制制定该方式.

     

3.2.1 并行GC 

 

      基于 Mark - Compact 实现.

      过程:

      (1) 将代空间分区域(区域个数和并行GC的线程数相同),然后使用多线程扫描标记着色对象,

          同时更新其所在region的存活大小及位置.

      (2) 确定压缩移动的region(通常旧生代左边存放的是一些活跃对象(不容易死的)

          因此这部分对象所在的region通常不压缩)的region源和region目的地.

          该过程目前为单线程进行.

      (3) 基于(2)中的分析信息进行对象的移动和region的回收.

          

      并行GC与之前的串行GC相比,大部分时候是多线程的,对应用造成的暂停时间会缩短.

      但是由于旧生代较大,再扫描和标识对象上需要话费较长时间.

      

      通过 -XX:+UseParallelGC 或 -XX:+UseParallelOldGC 来强制制定.

      两者区别:

      -XX:+UseParallelOldGC同时激活新生代并行垃圾回收和老年代的并行垃圾回收,

      亦即,Minor GC和Full GC都是多线程的;

      -XX:+UseParallelGC只会激活新生代的并行垃圾回收(旧生代使用的是Serial GC)。

      也就是使用了-XX:+UseParallelOldGC会自动激活-XX:+UseParallelGC。

      

      UseParallelGC would result in parallel young + serial old  and 

      UseParallelOldGC in parrallel young + parralel old gcs.

      

      参考: 

      oracle官方文档:

      [读书笔记]《Java Performance》GC(1)

      use UseParallelOldGC instead of UseParallelGC #1105

      Should we use UseParallelOldGC instead of UseParallelGC in hornetq user manual?:

 

3.2.3 并发(CMS Concurrent Mark-Sweep GC)  

 

     基于Mark-Sweep方式, 该方式可以减少GC应用暂停时间.

     Mark-Sweep 可能会产生内存碎片.

     并行 与 并发 区别在于,并行时 只有 垃圾回收线程运行,应用暂停了.

     而并发 时 应用线程 和 垃圾回收线程可同时执行.

     过程:

     (1) 第一次标记,暂停应用,只标记存活的根对象(速度快,暂停时间短,因为根对象毕竟不太多)

     (2) 并发标记 根据(1)的根对象,标记所有从根对象能够引用到的对象(耗时操作,并发进行,不停应用)

     (3) 重新标记,暂停应用,重新标记在步骤(2)进行时可能出现的新的类似与(1)中的根对象

         以及该根对象可达的所有存活对象,并对引用关系可能发生的变化做一些额外处理

         (需要处理的对象也是少数,因而速度快,暂停时间短)

     (4) 并发收集(耗时操作,并发进行,不停应用)

     

     虽然有两次暂停,但是暂停时间都比较短,耗时长的都是并发执行的.

     

     CMS方式的GC之后通常会产生内存碎片,因此CMS提供了内存碎片整理功能.

     这个内存整理功能在没有使用CMS时也可以使用,可以通过

     -XX:+UseCMSCompactAtFullCollection 在每次full gc之后都进行内存整理.

     也可以指定-XX:+CMSFullGCsBeforeCompact=3来指定在若干次full gc之后

     进行内存碎片整理.

     

     使用:-XX:+UseComcMarkSweepGC来强制使用CMS 方式的GC,默认开启的线程数为:

     (并行 GC线程数 + 3) / 4,可通过-XX:+ParallelCMSThreads=10来强制指定.

         

     CMS GC的触发条件不是旧生代满了,而是当旧生代已用空间达到参数: 

     -XX:CMSInitiatingOccupancyFraction设置的百分比.比如,默认

     -XX:CMSInitiatingOccupancyFraction=68%,则旧生代总工1000M,在已用空间达680M时

     触发CMS GC.还有一种方式,是JVM自行触发,指JVM根据之前GC的频率及旧生代的增长趋势

     来评估决定什么时候执行CMS GC,如果不希望JVM自行触发CMS GC,可以设置参数:

     -XX:+UseCMSInitiatingOccupancyOnly=true设置.

     

     可以通过设置参数-XX:+CMSPermGenSweepingEnabled使得持久代的GC也使用CMS.

     持久代GC默认是使用Full GC.

     

     

4. GC触发条件

 

   (1) 通常JVM在为对象分配空间是在新生代的Eden部分分配的.

       当Eden的剩余空间已经不足以放下一个新对象时会触发Minor GC.

   

   (2) 发生Minor GC时,Eden和S0(或S1)上的存活对象会被拷贝到S1(或S0)上.

       当S1(或S0)的剩余空间不足以容纳要拷贝的对象时,对象被直接拷贝到

       旧生代上;

       

       当经历了若干次(具体的次数可以通过-XX:MaxTenuringThreshold参数配置,这里配置的是最大值,

       也就是说,假如该值配置的5,则可能经历3次Minor GC后,对象就被拷贝到旧生代了,但最多不超过5次)

       的Minor GC时,S1(或S0)上仍然存活的对象会被拷贝到旧生代上;

       

       当Minor GC采用串行GC时,可以通过配置JVM参数:-XX:PretenureSizeThreshold

       使得对象大小超过这个数值时,对象直接在旧生代上分配空间.

       

       当Minor GC采用并行回收(Parallel Scavenge)GC,在Eden空间不够,在要分配空间的对象大小

       超过Eden空间一半时,直接在旧生代上分配(不受-XX:PretenureSizeThreshold这个参数控制了).

       

   (3) 当旧生代上空间不足以容纳要拷贝的对象时,会触发 Major GC.

       CMS GC的触发条件不是旧生代满了,而是当旧生代已用空间达到参数: 

       -XX:CMSInitiatingOccupancyFraction设置的百分比.比如,默认

       -XX:CMSInitiatingOccupancyFraction=68%,则旧生代总工1000M,在已用空间达680M时

       触发CMS GC.还有一种方式,是JVM自行触发,指JVM根据之前GC的频率及旧生代的增长趋势

       来评估决定什么时候执行CMS GC,如果不希望JVM自行触发CMS GC,可以设置参数:

       -XX:+UseCMSInitiatingOccupancyOnly=true设置.

   

   (4) 在持久代空间不足时也触发Full GC(比如Load一个class后导致持久代空间不足,或者反射调用).

       可以通过设置参数-XX:+CMSPermGenSweepingEnabled,使用CMS收集持久代的类.

       

   (5) Full Gc 触发情况

   

      a. 代码中显示执行System.gc();

      b. 旧生代空间不足

      c. 持久代空间满了(没有设置-XX:+CMSPermGenSweepingEnabled)

      c. CMS GC时出现promotion failed 和 concurrent mode failure

         promotion failed是在执行Minor GC时,Survivor放不下,而此时旧生代也放不下时造成的

         concurrent mode failure 是在执行CMS GC的过程中,同时有对象要放入旧生代,此时旧生代

         空间不足造成的.

      d. 统计得到Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间.

    

5. 示例代码

 

   使用myeclipse测试代码,通过Run -> Open run dialogue 打开运行对话框,在

   Arguments选项卡的vmarguments中设置JVM执行参数:

   常用参数:

    -Xms20m (堆内存最小空间) 

    -Xmx20m (堆内存最大空间) 

    -Xmn10m (堆内存 新生代空间) 

-XX:SurvivorRatio=10(eden 和 Survivor空间大小比值,默认值8) 

-XX:InitialSurvivorRatio=10(并行GC时用到)

-XX:+UseConcMarkSweepGC(使用CMS GC)  

-verbose:gc 

-XX:+PrintGCDetails (打印GC详细信息)

-XX:+PrintGC 

-XX:+PrintGCTimeStamps (打印GC信息时打印相对时间)

-XX:+PrintGCDateStamps (打印GC信息时,打印详细日期时间)

-XX:+UseCMSCompactAtFullCollection (Full GC时使用GMS 整理内存碎片)

-XX:+PrintGCApplicationStoppedTime (打印GC时应用暂停时间)

-XX:+PrintGCApplicationConcurrentTime (GC之间运行了多少时间)

-Xloggc:D:/D/gc.log (将GC日志输出到文件,指定这个参数之后,控制台中不再打印GC日志了)

 

5.1 Minor GC触发示例:Eden 空间不足时触发Minor GC

 

   

package jvm;

/**
 * 
 * 1. Eden 空间不足时触发Minor GC  
 * JVM参数:
 * -Xms40m
 * -Xmx40m
 * -Xmn16m
 * -XX:+UseParallelGC
 * -verbose:gc 
 * -XX:+PrintGCDetails
 * 此时Eden为12M,Survivor都是2M.
 * 
 * 输出信息如下:
 * 
mino gc should happen
[GC [PSYoungGen: 11509K->1200K(14336K)] 11509K->1200K(38912K), 0.0086913 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
mino gc should happen
[GC [PSYoungGen: 12589K->1184K(14336K)] 12589K->1184K(38912K), 0.0043232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 14336K, used 2453K [0x08200000, 0x09200000, 0x09200000)
  eden space 12288K, 10% used [0x08200000,0x0833d780,0x08e00000)
  from space 2048K, 57% used [0x09000000,0x09128050,0x09200000)
  to   space 2048K, 0% used [0x08e00000,0x08e00000,0x09000000)
 PSOldGen        total 24576K, used 0K [0x06a00000, 0x08200000, 0x08200000)
  object space 24576K, 0% used [0x06a00000,0x06a00000,0x08200000)
 PSPermGen       total 12288K, used 2087K [0x02a00000, 0x03600000, 0x06a00000)
  object space 12288K, 16% used [0x02a00000,0x02c09c10,0x03600000)
 *
 *使用 jstat工具查看可以看到YGC 发生了2次,耗时分别为19毫秒和26毫秒.
 *
 >jstat -gcutil 110788 2000
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
  0.00  87.90  22.17   0.00  46.22      1    0.019     0    0.000    0.019
  0.00  87.90  30.51   0.00  46.22      1    0.019     0    0.000    0.019
  0.00  87.90  40.88   0.00  46.23      1    0.019     0    0.000    0.019
  0.00  87.90  49.21   0.00  46.23      1    0.019     0    0.000    0.019
  0.00  87.90  58.57   0.00  46.26      1    0.019     0    0.000    0.019
  0.00  87.90  58.57   0.00  46.26      1    0.019     0    0.000    0.019
  0.00  87.90  59.59   0.00  46.26      1    0.019     0    0.000    0.019
  0.00  87.90  59.59   0.00  46.26      1    0.019     0    0.000    0.019
  0.00  87.90  60.61   0.00  46.27      1    0.019     0    0.000    0.019
  0.00  87.90  60.61   0.00  46.27      1    0.019     0    0.000    0.019
  0.00  87.90  62.65   0.00  46.32      1    0.019     0    0.000    0.019
  0.00  87.90  62.65   0.00  46.32      1    0.019     0    0.000    0.019
  0.00  87.90  63.67   0.00  46.35      1    0.019     0    0.000    0.019
  0.00  87.90  63.67   0.00  46.36      1    0.019     0    0.000    0.019
  0.00  87.90  64.69   0.00  46.38      1    0.019     0    0.000    0.019
  0.00  87.90  73.03   0.00  46.38      1    0.019     0    0.000    0.019
  0.00  87.90  74.05   0.00  46.40      1    0.019     0    0.000    0.019
  0.00  87.90  82.38   0.00  46.40      1    0.019     0    0.000    0.019
  0.00  87.90  92.76   0.00  46.43      1    0.019     0    0.000    0.019
 87.12   0.00   8.33   0.00  46.43      2    0.026     0    0.000    0.026
 87.12   0.00  20.70   0.00  46.48      2    0.026     0    0.000    0.026
 87.12   0.00  29.03   0.00  46.48      2    0.026     0    0.000    0.026
 87.12   0.00  38.19   0.00  46.53      2    0.026     0    0.000    0.026
 87.12   0.00  46.52   0.00  46.53      2    0.026     0    0.000    0.026
 87.12   0.00  56.50   0.00  46.61      2    0.026     0    0.000    0.026
 87.12   0.00  64.84   0.00  46.61      2    0.026     0    0.000    0.026
 87.12   0.00  74.82   0.00  46.70      2    0.026     0    0.000    0.026
 87.12   0.00  74.82   0.00  46.70      2    0.026     0    0.000    0.026
 87.12   0.00  79.29   0.00  46.80      2    0.026     0    0.000    0.026
 87.12   0.00  79.29   0.00  46.80      2    0.026     0    0.000    0.026
 87.12   0.00  80.04   0.00  46.80      2    0.026     0    0.000    0.026
 87.12   0.00  80.04   0.00  46.80      2    0.026     0    0.000    0.026
 87.12   0.00  81.55   0.00  46.81      2    0.026     0    0.000    0.026
 87.12   0.00  81.55   0.00  46.81      2    0.026     0    0.000    0.026
 87.12   0.00  82.32   0.00  46.81      2    0.026     0    0.000    0.026
 87.12   0.00  82.32   0.00  46.81      2    0.026     0    0.000    0.026
 87.12   0.00  83.84   0.00  46.81      2    0.026     0    0.000    0.026
 87.12   0.00  92.18   0.00  46.81      2    0.026     0    0.000    0.026
 87.12   0.00  92.93   0.00  46.82      2    0.026     0    0.000    0.026
 */

public class MinorGCDemo
{
  private static void happenMinorGC(int happenMinorGCIndex) throws Exception
  {
    for(int i=0;i<happenMinorGCIndex;i++)
    {
      if(i==happenMinorGCIndex - 1)
      {
        Thread.sleep(20000);
        System.out.println("minor gc should happen");
      }
      new MemoryObject(1024 * 1024);
      Thread.sleep(2000);
    }
  }
  
  public static void main(String[] args) throws Exception
  {
    MemoryObject object = new MemoryObject(1024 * 1024);//占用1M空间的对象
    for(int i=0;i<2;i++)
    {
      happenMinorGC(11); 
      //第一次分配了11个1M 加上之前分配的1M在分配第11个时,
      //达到eden的最大空间12M,输出minor gc should happen
      //后进行Minor GC
      Thread.sleep(2000);
    }
  }
}

class MemoryObject
{
  private byte[] bytes;
  
  public MemoryObject(int objectSize)
  {
    this.bytes = new byte[objectSize];
  }
}

 

 

5.2 Minor Gc时,survivor 空间不足,对象直接进入旧生代.    

  

package jvm;

/**
 * 
 * 2. Minor Gc时,survivor 空间不足,对象直接进入旧生代.
 * 
 * JVM参数:
 * -Xms40m
 * -Xmx40m
 * -Xmn16m
 * -XX:+UseParallelGC
 * -verbose:gc 
 * -XX:+PrintGCDetails
 *运行结果如下,其中PSOldGen        total 24576K, used 2048K [0x06a00000, 0x08200000, 0x08200000) 说明旧生代已占有2M空间
 *minor gc should happen
[GC [PSYoungGen: 11509K->1200K(14336K)] 11509K->3248K(38912K), 0.0115163 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 
Heap
 PSYoungGen      total 14336K, used 2469K [0x08200000, 0x09200000, 0x09200000)
  eden space 12288K, 10% used [0x08200000,0x0833d780,0x08e00000)
  from space 2048K, 58% used [0x08e00000,0x08f2c050,0x09000000)
  to   space 2048K, 0% used [0x09000000,0x09000000,0x09200000)
 PSOldGen        total 24576K, used 2048K [0x06a00000, 0x08200000, 0x08200000)
  object space 24576K, 8% used [0x06a00000,0x06c00010,0x08200000)
 PSPermGen       total 12288K, used 2087K [0x02a00000, 0x03600000, 0x06a00000)
  object space 12288K, 16% used [0x02a00000,0x02c09c48,0x03600000)
  
  jstat输出为:
  C:\Documents and Settings\10106511>jstat -gcutil 108148 2000
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00  90.04   0.00  46.21      0    0.000     0    0.000    0.000
  0.00   0.00  98.38   0.00  46.21      0    0.000     0    0.000    0.000
  0.00   0.00  98.38   0.00  46.24      0    0.000     0    0.000    0.000
  0.00   0.00  98.38   0.00  46.24      0    0.000     0    0.000    0.000
  0.00  89.07  12.62   8.33  46.26      1    0.015     0    0.000    0.015
  0.00  89.07  12.62   8.33  46.26      1    0.015     0    0.000    0.015
  0.00  89.07  23.24   8.33  46.28      1    0.015     0    0.000    0.015
  0.00  89.07  23.24   8.33  46.28      1    0.015     0    0.000    0.015
  0.00  89.07  24.51   8.33  46.32      1    0.015     0    0.000    0.015
  可以看到进行了一次Minor(YGC由0到1后) O字段从0到8.33%,表对象被复制到旧生代了.
 */
public class MinorSurvivorDemo
{
  private static void happenMinorGC(int happenMinorGCIndex) throws Exception
  {
    for(int i=0;i<happenMinorGCIndex;i++)
    {
      if(i==happenMinorGCIndex - 1)
      {
        Thread.sleep(2000);
        System.out.println("minor gc should happen");
      }
      new MemoryObject(1024 * 1024);
    }
  }
  
  public static void main(String[] args) throws Exception
  {
    MemoryObject object = new MemoryObject(1024 * 1024);//1M
    MemoryObject object2 = new MemoryObject(1024 * 1024 * 2);//2M
    happenMinorGC(9);
    //分配到第九个对象时,Eden满了(12M),导致GC,复制对象到Survivor时,先复制1M的(达到Survivor的空间了),
    //导致Survivor满了,然后将2M对象复制到旧生代.
    Thread.sleep(2000);
  }
}

 

 

5.3 测试使用不同GC方式时,输出的GC日志格式不同

package jvm;

/**
 * 
 * 测试使用不同GC方式时,输出的GC日志格式不同
 * 
 * 1. 使用串行GC -XX:+UseSerialGC
 *   vm参数如下:
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseSerialGC
-XX:SurvivorRatio=6
-verbose:gc 
-XX:+PrintGC
-XX:+PrintGCDetails
 * 此时Eden为12M,Survivor都是2M.
 *输出信息:
 *minor gc should happen
[GC [DefNew: 11509K->1173K(14336K), 0.0045310 secs] 11509K->1173K(38912K), 0.0045777 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
...
表示 使用-XX:+UseSerialGC时,GC日志中前缀使用的是DefNew
[DefNew: 11509K->1173K(14336K), 0.0045310 secs] 表示 Minor GC使得新生代已用空间从11509K变成1173K,可用空间14336
11509K->1173K(38912K) 表示GC使得堆空间的已用空间从11509K变成1173K,总可用空间为(38912K)
0.0045777 secs 表示本次GC总耗时.
[Times: user=0.00 sys=0.00, real=0.00 secs]  表示GC时CPU耗时占 CPU user和sys的百分比,以及总耗时

2.使用并行回收GC -XX:+UseParallelGC
*   vm参数如下:
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseParallelGC
-verbose:gc 
-XX:+PrintGC
-XX:+PrintGCDetails
输出:
minor gc should happen
[GC [PSYoungGen: 11509K->1200K(14336K)] 11509K->3248K(38912K), 0.0049179 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
.....

3.使用并行GC -XX:+UseParNewGC
*   vm参数如下:
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseParNewGC
-XX:SurvivorRatio=6
-verbose:gc 
-XX:+PrintGC
-XX:+PrintGCDetails
输出为:
minor gc should happen
[GC [DefNew: 11509K->1173K(14336K), 0.0034538 secs] 11509K->1173K(38912K), 0.0035021 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
...
由 DefNew 可知,使用-XX:+UseParNewGC时,Minor GC使用的是串行方式

4. 使用并行GC -XX:+UseParallelOldGC

-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseParallelOldGC
-XX:SurvivorRatio=6
-verbose:gc 
-XX:+PrintGC
-XX:+PrintGCDetails
输出:
minor gc should happen
[GC [PSYoungGen: 11509K->1200K(14336K)] 11509K->1200K(38912K), 0.0029191 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
...
说明使用-XX:+UseParallelOldGC时,Minor GC使用的是并行回收GC -XX:+UseParallelGC

5. 单独使用 -XX:+UseConcMarkSweepGC(Major GC方式)
-Xms40m
-Xmx40m
-Xmn16m
-XX:+UseConcMarkSweepGC
-XX:SurvivorRatio=6
-verbose:gc 
-XX:+PrintGC
-XX:+PrintGCDetails
输出为:
minor gc should happen
[GC [DefNew: 11509K->1173K(14336K), 0.0046844 secs] 11509K->1173K(38912K), 0.0047808 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
...
说明 Minor GC使用的是串行GC,-XX:+UseSerialGC,即,单独配置-XX:+UseConcMarkSweepGC时,
默认-XX:+UseConcMarkSweepGC和-XX:+UseSerialGC配合使用

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC 只有这种组合是合法的,也可以省略-XX:+UseParNewGC
下面组合都不行
-XX:+UseConcMarkSweepGC -XX:+UseParallelOldGC
-XX:+UseConcMarkSweepGC -XX:+UseParallelGC
-XX:+UseConcMarkSweepGC -XX:+UseSerialGC

 */
public class MutilGCLog
{
  private static void happenMinorGC(int happenMinorGCIndex) throws Exception
  {
    for(int i=0;i<happenMinorGCIndex;i++)
    {
      if(i==happenMinorGCIndex - 1)
      {
        Thread.sleep(2000);
        System.out.println("minor gc should happen");
        new MemoryObject(1024 * 1024 * 3);
      }
      new MemoryObject(1024 * 1024);
      //Thread.sleep(5000);
    }
  }
  
  public static void main(String[] args) throws Exception
  {
    MemoryObject object = new MemoryObject(1024 * 1024);
    happenMinorGC(11);
    Thread.sleep(2000);
  }
}

 

 

 

 

 

0
1
分享到:
评论

相关推荐

    JVM_GC_-调优总结.pdf

    ### JVM_GC_调优总结 #### 一、GC(Garbage Collection)概述 **1.1 GC的概念** - **定义**: GC(Garbage Collection),即垃圾收集器,用于跟踪内存中的对象,并自动回收那些不再被其他对象引用的对象,释放这...

    jvm 参数及gc详解

    总结,理解并掌握JVM参数和GC机制是Java开发中的重要技能。通过合理配置JVM参数,我们可以有效控制内存使用,优化程序性能,并减少垃圾收集带来的负面影响。同时,根据应用特性选择合适的垃圾收集策略,能进一步提高...

    深入JVM内核—原理、诊断与优化视频教程-4.GC算法与种类

    总结,JVM内核的深入理解和GC的精通对于Java开发者至关重要。通过学习“深入JVM内核—原理、诊断与优化视频教程”,可以提升对JVM工作的理解,从而更好地优化应用性能,减少系统停顿,提高用户体验。通过实践和研究...

    JVM垃圾回收机制与GC性能调优

    总结来说,理解JVM堆的结构和GC的工作机制对于优化Java应用性能至关重要。调整合适的堆大小和内存分配策略可以有效减少垃圾回收的频率和时间,提高系统响应速度。此外,监控GC日志,分析GC行为,以及使用适当的GC...

    JVM、GC详解及调优

    总结,理解和掌握JVM的工作原理以及GC机制,对于优化Java应用性能至关重要。通过细致的调优,可以有效减少垃圾收集的开销,提升系统的稳定性和响应速度。同时,持续监控和分析JVM运行状态,能帮助我们及时发现并解决...

    JVM调优总结PDF,带原理图

    垃圾回收(GC)作为JVM的重要组成部分,其效率直接影响到程序的响应时间和资源利用率。本文旨在通过对JVM调优的基础概念和常见的垃圾回收算法进行深入剖析,帮助读者更好地理解和掌握JVM调优的关键技术。 #### 二、...

    JVM调优总结 Xms -Xmx -Xmn -Xss

    ### JVM调优总结:Xms、Xmx、Xmn、Xss 在Java虚拟机(JVM)的运行过程中,合理的参数配置对于提高程序性能至关重要。本文将对JVM调优中的几个关键参数进行深入解析,包括-Xms、-Xmx、-Xmn和-Xss等,帮助开发者更好...

    JVM、GC详解及调优.pdf

    本文档详细讲解了JVM(Java Visual Mathine)的方方面面,首先由java的特性来描绘JVM的大致应用,再详细阐释了 JVM 的原理及内存管理机制和调优,讲述了与JVM密切相关的 Java GC 机制,最后对 JVM 调优进行了总结。...

    JVM——总结思维导图

    JVM——总结思维导图

    JVM调优总结.rar

    【JVM调优总结】 Java虚拟机(JVM)是Java程序运行的基础,它负责解析字节码并将其转换为机器可执行的指令。JVM调优是优化Java应用程序性能的关键步骤,尤其对于大型分布式系统而言,良好的JVM配置可以显著提高系统...

    JVM性能调优总结.docx

    JVM性能调优总结 JVM性能调优是Java开发中非常重要的一方面,直接影响到系统的性能和稳定性。本文将总结JVM性能调优的经验和技巧,并提供一些实用的配置参数和建议。 一、堆大小设置 堆大小是JVM性能调优中的一个...

    JVM体系结构与GC调优总结

    JVM体系结构与GC调优总结,很详尽,面试必备呀,值得拥有!

    深入虚拟机---JVM调优总结(摘自网上网上大牛分享).pdf

    在深入讨论JVM(Java虚拟机)调优之前,我们有必要先了解一下虚拟机的基本概念和堆栈...通过上述的分析和总结,我们可以得出,JVM调优是一个涉及多方面知识的复杂过程,需要开发者具备扎实的理论基础和丰富的实践经验。

    Java-JVM调优总结

    ### Java-JVM调优总结 #### 一、引言 在现代软件开发中,Java 作为一种广泛使用的编程语言,其应用程序的性能优化至关重要。而 JVM(Java Virtual Machine)作为 Java 程序运行的基础环境,对其进行合理的调优可以...

    JVM&amp;g1gc;带书签,完整版本

    "JVM&g1gc;带书签,完整版本"的学习资料提供了深入了解JVM内存管理和G1垃圾收集器的详细内容。通过对G1的理解和实践,开发者可以更好地优化Java应用的性能,降低垃圾收集对应用运行的影响,实现更高效的内存管理。这...

    JVM入门总结 .pdf

    JVM(Java虚拟机)是Java程序的...JVM入门总结涵盖了从JVM基础到高级垃圾回收的各个方面。掌握了这些知识点,可以帮助我们更好地了解Java程序的运行机制,优化内存使用,以及合理选择垃圾回收策略,从而提升程序性能。

    JVM调优与内存管理总结

    Java虚拟机(JVM)调优与内存管理是优化Java应用程序性能的关键环节。JVM内存主要分为新生代、老年代和持久代,每个区域都有其特定的垃圾回收策略。 1. 引用计数法(Reference Counting):这是一种简单的垃圾回收...

    jvm相关总结

    Java虚拟机(JVM)是Java程序运行的基础,它是一个抽象的计算机系统,负责执行Java字节码。作为“翻译家”,JVM遵循Java语言规范,将编写的Java代码转换成机器可理解的指令。 ## 一、JVM概念与历史 JVM的概念源于...

    JVM性能调优-JVM内存整理及GC回收.pdf_java_jvm_

    总结来说,JVM性能调优是多方面的工作,包括理解内存结构、选择合适的垃圾收集器、调整内存参数以及优化代码实现。通过细致入微的调优,可以显著提升Java应用的性能和稳定性。这份PDF资料将详细介绍这些关键点,帮助...

    JVM调优总结(4)分代垃圾回收Java开发Java经验技

    本篇文章将详细讲解"JVM调优总结(4)分代垃圾回收"这一主题,旨在帮助Java开发者掌握更加高效、稳定的应用运行策略。 一、分代垃圾回收理论基础 Java的内存管理主要依靠垃圾回收机制,它自动回收不再使用的对象,...

Global site tag (gtag.js) - Google Analytics