JVM參數調優-設置堆、新生代、老年代、持久代大小
一、根據程序的運行狀況查看其活躍的數據量
①、活躍的數據:
1.應用程序運行於穩定狀態時,老年代占用的java堆大小
2.應用程序運行於穩定狀態時,永久代占用的java堆大小
其實就是FullGc后這2個數據的大小
②、動手測試:
1.測試代碼:
-
public class A {
-
int[] storage = new int[102400];
-
int[] extra = new int[200000];
-
-
public int[] execute() {
-
try {
-
Thread.sleep( 10);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
return storage;
-
}
-
}
-
import java.util.LinkedList;
-
import java.util.Queue;
-
-
public class Test {
-
-
public static void main(String[] args) {
-
Queue< int[]> queue = new LinkedList<int[]>();
-
while (true) {
-
int[] tmp=new A().execute();
-
if (queue.size() > 1000) {
-
queue.poll();
-
} else {
-
queue.offer(tmp);
-
}
-
}
-
-
}
-
}
2.參數配置:
3.測試的結果
4.結果分析
可以看到老年代的大小為404211K,持久代的大小為8888K
二、通過活躍的數據配置堆以及其他參數
通用法則1:
將java堆的初始值-Xms和最大值-Xmx設置為老年代活躍數據大小的3~4倍
所以此處就設置 -Xms1600m,-Xmx1600m
在以上的測試結果中可以看到原始的堆大小為1675m左右,是比較接近的。
通用法則2:
永久帶的初始值-XX:PermSize及最大值-XX:MaxPermSize應該比永久代活躍數據大1.2~1.5倍
所以此處就設置-XX:PermSize=13m,-XX:MaxPermSize=13m
補充法則:
新生代空間應該為老年代空間活躍數據的1~1.5倍
此處老年代為400m,新生代就為600m
如果java堆的初始值及最大值為活躍數據的3~4倍,新生代為活躍數據的1~1.5倍時,老年代應設置為活躍數據大小的2~3倍
參考表
四、日志分析
分析:
1.看頻率,可以發現基本上是4秒進行一次Gc
2.看耗時,可以發現基本上是需要0.037秒
當前的虛擬機設置為:
堆:1600M
年輕代:600M
年老代:1000M
優化
需求1:
要求MinorGc的響應時間小於0.02秒
分析:
需要減少MinorGc的時間,那一定是因為年輕代的容量太大了,以至於一次清理耗時較久。
所以需要較少年輕代的大小,雖然這樣會增加MinorGc的頻率。
因為目前耗時是0.037,幾乎是2倍於目標,所以將年輕代的大小減少為1/2,保持年老帶不變。
-Xms1300m -Xmx1300m -Xmn300m
需求2:
要求MinorGc的響應時間小於0.1秒
既然對響應要求不是那么嚴格,就可以增大年輕代的空間,減少minorGc的頻率。
現在是0.037,目標是0.1。假定是正比,那么可以把年輕代的大小提2.5倍(+900m)。
-Xms2500,m -Xmx2500m -Xmn1500m
准則
1.老年代空間大小不應該小於活躍數據大小的1.5倍
2.新生代空間至少應為Java堆的10%,,通過-Xmx和-Xms可以設定該值。
3.增大Java堆大小時,需要注意不要超過JVM可用的物理內存數。
這個階段中,如果只考慮minorGc引起的延遲,而調整新生代的大小又無法滿足應用程序的平均停頓時間或延遲性要求,就只能修改應用程序或者改變JVM的部署模式,在多個JVM上部署應用程序,或者修改應用程序的平均延遲性要求。
五.計算老年代
日志圖:
1.假如沒有FullGc,如何計算老年代需要多少時間裝滿?
(不看第一條和最后一條數據,分析)通過MinorGc計算每次老年代的增量
老年代的增量 = 堆的總量 - 新生代的剩余量(souvivor區)
這樣可以得到幾乎每次minorGc老年代增加85m空間,而minorGc每4秒一次。
老年代的總量:
1654272 - 601088 = 1053184k =1028m
那么填滿老年區需要
1028 / 85 * 4 = 48s