JAVA垃圾收集器之ParallelScavenge收集器
Parallel Scavenge收集器是JAVA虛擬機器中垃圾收集器的一種。和ParNew收集器類似,是一個新生代收集器。使用複製演算法的並行多線程收集器。
1、特點
Parallel Scavenge收集器的關注點與其他收集器不同, ParallelScavenge收集器的目標則是達到一個可控制的輸送量(Throughput)。所謂輸送量就是CPU用於運行使用者代碼的時間與CPU總消耗時間的比值,即輸送量 = 運行使用者代碼時間 /(運行使用者代碼時間 +垃圾收集時間),虛擬機器總共運行了100分鐘,其中垃圾收集花掉1分鐘,那輸送量就是99%。
由於與輸送量關係密切,Parallel Scavenge收集器也經常被稱為“輸送量優先”收集器。
該垃圾收集器,是JAVA虛擬機器在Server模式下的預設值,使用Server模式後,java虛擬機器使用Parallel Scavenge收集器(新生代)+ Serial Old收集器(老年代)的收集器組合進行記憶體回收。
2、使用情境
主要適應主要適合在後台運算而不需要太多互動的任務。
比如需要與使用者互動的程式,良好的響應速度能提升使用者的體驗;而高輸送量則可以最高效率地利用CPU時間,儘快地完成程式的運算任務等。
3、重要參數
重要的參數有三個,其中兩個參數用於精確控制輸送量,分別是控制最大垃圾收集停頓時間的-XX:MaxGCPauseMillis參數及直接設定輸送量大小的 -XX:GCTimeRatio參數。另外一個是UseAdaptiveSizePolicy切換參數。
MaxGCPauseMillis參數允許的值是一個大於0的毫秒數,收集器將儘力保證記憶體回收花費的時間不超過設定值。不過大家不要異想天開地認為如果把這個參數的值設定得稍小一點就能使得系統的垃圾收集速度變得更快,GC停頓時間縮短是以犧牲輸送量和新生代空間來換取的:系統把新生代調小一些,收集300MB新生代肯定比收集500MB快吧,這也直接導致垃圾收集發生得更頻繁一些,原來10秒收集一次、每次停頓100毫秒,現在變成5秒收集一次、每次停頓70毫秒。停頓時間的確在下降,但輸送量也降下來了。
GCTimeRatio參數的值應當是一個大於0小於100的整數,也就是垃圾收集時間佔總時間的比率,相當於是輸送量的倒數。如果把此參數設定為19,那允許的最大GC時間就佔總時間的5%(即1 /(1+19)),預設值為99,就是允許最大1%(即1 /(1+99))的垃圾收集時間。
-XX:+UseAdaptiveSizePolicy是一個切換參數,當這個參數開啟之後,就不需要手工指定新生代的大小(-Xmn)、Eden與Survivor區的比例(-XX:SurvivorRatio)、晉陞老年代對象年齡(-XX:PretenureSizeThreshold)等細節參數了,虛擬機器會根據當前系統的運行情況收集效能監控資訊,動態調整這些參數以提供最合適的停頓時間或最大的輸送量,這種調節方式稱為GC自適應的調節策略(GC Ergonomics)。
4、自適應調節策略
Parallel Scavenge收集器能夠配合自適應調節策略,把記憶體管理的調優任務交給虛擬機器去完成。只需要把基本的記憶體資料設定好(如-Xmx設定最大堆),然後使用MaxGCPauseMillis參數(更關注最大停頓時間)或GCTimeRatio參數(更關注輸送量)給虛擬機器設立一個最佳化目標,那具體細節參數的調節工作就由虛擬機器完成了。自適應調節策略也是Parallel Scavenge收集器與ParNew收集器的一個重要區別。
5、具體使用樣本
原始碼
package com.gc;
import java.util.ArrayList;
import java.util.List;
/**
* 簡單的JAVA虛擬機器記憶體回收,Parallel Scavenge收集器的使用
* 運行參數,見具體方法,注意:需要開啟server模式才能使用
* @author 範芳銘
*/
public class EasyParallelScavenge {
public byte[] placeHolder =new byte[64 * 1024]; //預留位置
public static voidmain(String[] args) throws Exception{
outOfMemoryByExpansionSize();
}
/**
* JAVA虛擬機器的大小適當可擴充,其中Xms30m,Xmx400m
* 參數:-server -Xms30m-Xmx100m -XX:+UseParallelGC -XX:+PrintGCDetails
* @author 範芳銘
*/
private static voidoutOfMemoryByExpansionSize() throws Exception{
List<EasyParallelScavenge>list = new ArrayList<EasyParallelScavenge>();
while(true){
EasyParallelScavengeserial = new EasyParallelScavenge();
list.add(serial);
Thread.sleep(10);//停頓10毫秒
}
}
}
參數說明:
-server 伺服器模式運行
-Xms30m 最小JAVA虛擬機器記憶體30M
-Xmx100m最大JAVA虛擬機器記憶體100M
-XX:+UseParallelGC 明確指定使用Parallel Scavenge收集器
-XX:+PrintGCDetails 列印回收情況
運行結果如下:
…[GC [PSYoungGen: 7449K->3728K(7552K)] 66980K->66980K(75136K),0.0022792 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC [PSYoungGen:7443K->3728K(7552K)] 70695K->70715K(75136K), 0.0027722 secs] [Times:user=0.00 sys=0.03, real=0.00 secs]
[Full GC [PSYoungGen:3728K->3136K(7552K)] [PSOldGen: 66986K->67563K(76928K)]70715K->70700K(84480K) [PSPermGen: 2088K->2088K(16384K)], 0.0038774 secs][Times: user=0.00 sys=0.00, real=0.00 secs]
[GC [PSYoungGen: 3714K->3744K(7552K)]71278K->71308K(84480K), 0.0017028 secs] [Times: user=0.00 sys=0.00,real=0.00 secs]
[GC [PSYoungGen:7459K->3744K(7552K)] 75023K->75025K(84480K), 0.0027427 secs] [Times:user=0.00 sys=0.00, real=0.00 secs]
[GC [PSYoungGen: 7459K->3744K(7552K)]78739K->78753K(84480K), 0.0048844 secs] [Times: user=0.03 sys=0.00,real=0.01 secs]
[Full GC [PSYoungGen:3744K->1728K(7552K)] [PSOldGen: 75009K->76922K(87488K)]78753K->78651K(95040K) [PSPermGen: 2088K->2088K(16384K)], 0.0107597 secs][Times: user=0.00 sys=0.00, real=0.01 secs]
[GC [PSYoungGen:3714K->3744K(7552K)] 80637K->80667K(95040K), 0.0015904 secs] [Times:user=0.00 sys=0.00, real=0.00 secs]
[GC [PSYoungGen:7459K->3728K(7552K)] 84382K->84372K(95040K), 0.0028244 secs] [Times:user=0.03 sys=0.00, real=0.00 secs]
[GC [PSYoungGen:7443K->3728K(7552K)] 88087K->88093K(95040K), 0.0023412 secs] [Times:user=0.00 sys=0.00, real=0.00 secs]
[Full GC [PSYoungGen:3728K->640K(7552K)] [PSOldGen: 84364K->87438K(91072K)]88093K->88078K(98624K) [PSPermGen: 2088K->2088K(16384K)], 0.0048474 secs][Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC [PSYoungGen:3714K->128K(7552K)] [PSOldGen: 87438K->91023K(91072K)]91153K->91151K(98624K) [PSPermGen: 2088K->2088K(16384K)], 0.0047349 secs][Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC [PSYoungGen:3714K->3714K(7552K)] [PSOldGen: 91023K->91023K(91072K)]94738K->94738K(98624K) [PSPermGen: 2088K->2088K(16384K)], 0.0031963 secs][Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC [PSYoungGen: 3714K->3649K(7552K)][PSOldGen: 91023K->91070K(91072K)] 94738K->94720K(98624K) [PSPermGen:2088K->2087K(16384K)], 0.0209529 secs] [Times: user=0.03 sys=0.00, real=0.02secs]
[Full GC [PSYoungGen:3713K->3713K(7552K)] [PSOldGen: 91070K->91070K(91072K)] 94784K->94784K(98624K)[PSPermGen: 2087K->2087K(16384K)], 0.0035128 secs] [Times: user=0.02sys=0.00, real=0.00 secs]
[Full GC [PSYoungGen:3713K->3713K(7552K)] [PSOldGen: 91070K->91070K(91072K)]94784K->94784K(98624K) [PSPermGen: 2087K->2087K(16384K)], 0.0027033 secs][Times: user=0.00 sys=0.00, real=0.00 secs]
Exception in thread "main"java.lang.OutOfMemoryError: Java heap space
atcom.gc.EasyParNew.<init>(EasyParNew.java:12)
atcom.gc.EasyParNew.outOfMemoryByExpansionSize(EasyParNew.java:39)
atcom.gc.EasyParNew.main(EasyParNew.java:14)
Heap
PSYoungGen total 7552K, used 3776K [0x0e4b0000, 0x0efc0000, 0x0efc0000)
eden space 3776K, 100% used [0x0e4b0000,0x0e860000,0x0e860000)
from space 3776K, 0% used [0x0ec10000,0x0ec10000,0x0efc0000)
to space 3776K, 0% used[0x0e860000,0x0e860000,0x0ec10000)
PSOldGen total 91072K, used 91070K [0x08bc0000, 0x0e4b0000, 0x0e4b0000)
object space 91072K, 99% used[0x08bc0000,0x0e4af980,0x0e4b0000)
6、和serial、parNew兩種新生代收集器的簡單區別
[GC [DefNew: 1986K->128K(2112K),0.0011191 secs] 27809K->27808K(30528K), 0.0011425 secs] [Times: user=0.00sys=0.01, real=0.00 secs]
和
[GC [ParNew: 1990K->132K(2112K),0.0007742 secs] 24112K->24110K(30528K), 0.0007964 secs] [Times: user=0.00sys=0.00, real=0.00 secs]
和
[GC [PSYoungGen:7449K->3728K(7552K)] 66980K->66980K(75136K), 0.0022792 secs] [Times:user=0.00 sys=0.00, real=0.00 secs]
GC[ParNew 表示使用的是parNew收集器。
GC[DefNew 表示用的是serial收集器。
[GC[PSYoungGen 表示用的是Parallel Scavenge收集器。