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.
參考:
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);
}
}