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);
  }
}

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章