在對於JVM而言,本身有兩種運行模式:單機版客戶端程序(client)、服務端程序(server)。
常用GC策略
GC策略調整參數
收集器參數設置
如果要想確認使用的GC處理,首先需要知道當前主機上可以支持的處理進程數量。
範例
範例1:取得可用的進程數量
Runtime.getRuntime().availableProcessors();
範例2:觀察使用的默認GC模式
public class TestGCDemo {
public static void main(String[] args) {
java.util.Random rand=new java.util.Random();
String str="hello world";
while(true){
str+=str+rand.nextInt(999999);
str.intern();//入池 ,強制性垃圾產生
}
}
}
運行參數設置 -Xmx10m -Xms10m -XX:+PrintGCDetails
輸出結果中會有如下幾個信息顯示:
[Full GC (Allocation Failure)
[PSYoungGen: 0K->0K(2048K)][ParOldGen: 4564K->4544K(7168K)] 4564K->4544K(9216K),[Metaspace: 3519K->3519K(1056768K)], 0.0149522 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
可以看到默認狀態下年輕代使用的是並行回收GC(ParallelScavenge)來進行垃圾釋放。
而老年代的回收默認使用的是“ParOldGen”,採用的是並行GC(Parallel MSC)完成的老年代處理。
上面只是基於我的電腦的默認策略,虛擬機會根據當前電腦的情況,來選擇合適的GC處理策略。因此,大部分而言,沒有必要調整處理策略。
範例3:使用串行GC
還是使用範例2的代碼,運行參數配置:
-Xmx10m -Xms10m -XX:+PrintGCDetails -XX:+UseSerialGC
運行輸出結果
[GC (Allocation Failure)
[DefNew: 2752K->320K(3072K), 0.0060972 secs] 2752K->1223K(9920K), 0.0062006 secs][Times: user=0.00 sys=0.00, real=0.01 secs]
[Full GC (Allocation Failure)
[Tenured: 4839K->4559K(6848K), 0.0075186 secs] 4839K->4559K(9920K),
[Metaspace: 3518K->3518K(1056768K)], 0.0075650 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
範例4:使用並行GC
還是使用範例2的代碼,運行參數配置:
-Xmx10m -Xms10m -XX:+PrintGCDetails -XX:+UseParNewGC
運行輸出結果
[GC (Allocation Failure)
[ParNew (promotion failed): 2175K->2175K(3072K), 0.0005994 secs][Tenured: 5948K->4860K(6848K), 0.0058181 secs] 5948K->4860K(9920K), [Metaspace: 3521K->3521K(1056768K)], 0.0064770 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[Full GC (Allocation Failure)
[Tenured: 4860K->4555K(6848K), 0.0054815 secs] 4860K->4555K(9920K), [Metaspace: 3521K->3521K(1056768K)], 0.0055406 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
還有一個警告
Java HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release
不建議使用了
範例5:使用CMS處理
GC策略調整參數
從上圖中可以看到CMS只對老年代的並行GC有效。
代碼還是使用範例2的代碼,運行參數配置:
-Xmx10m -Xms10m -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC
運行結果
[GC (CMS Initial Mark)
[1 CMS-initial-mark: 53960K(102400K)] 88784K(148480K), 0.0002741 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.006/0.049 secs]
[Times: user=0.19 sys=0.03, real=0.05 secs]
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-abortable-preclean-start]
[CMS-concurrent-abortable-preclean: 0.000/0.000 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.001/0.001 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
通過輸出結果,可以看到CMS會經歷如下幾個步驟:
- “CMS-concurrent-mark-start”:CMS標記開始
- “CMS-concurrent-mark”:表示開始進行標記,進入到了STW狀態(暫停)
- “CMS-concurrent-preclean-start”:預清理開始
- “CMS-concurrent-sweep-start”:開始進行無用對象清理
CMS執行流程:
CMS的處理適當性會好一些。不過這所有的GC策略都是現在正在常用的策略,都有缺點。實際開發中對於GC策略不建議手工修改,默認的一般比較好用,特殊處理情況除外。