概述
公司的江南白衣寫了一篇關鍵業務系統的JVM引數推薦(2016熱冬版)的文章,大牛的文章總是需要細細品讀。這篇文章介紹大量的JVM調優引數,內容也比較多,本文只是列出我自己能理解的一些引數,暫時理解不了的引數就只能等以後自己實力到家了,再慢慢補充上來。
效能調優引數
-XX:AutoBoxCacheMax
JAVA程式啟動的時候,會載入rt.jar這個核心包的,rt.jar包裡的Integer自然也是被載入到JVM中,Integer裡面有一個IntegerCache快取,如下:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}複製程式碼
IntegerCache有一個靜態程式碼塊,JVM在載入Integer這個類時,會優先載入靜態的程式碼。當JVM程式啟動完畢後, -128 ~ +127 範圍的數字會被快取起來,呼叫valueOf方法的時候,如果是這個範圍內的數字,則直接從快取取出。
超過這個範圍的,就只能構造新的Integer物件了。
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}複製程式碼
因此可以根據實際情況把AutoBoxCacheMax的值設定的大寫,比如江南白衣推薦的
-XX:AutoBoxCacheMax=20000複製程式碼
-XX:+AlwaysPreTouch
JAVA程式啟動的時候,雖然我們可以為JVM指定合適的記憶體大小,但是這些記憶體作業系統並沒有真正的分配給JVM,而是等JVM訪問這些記憶體的時候,才真正分配,這樣會造成以下問題。
1、GC的時候,新生代的物件要晉升到老年代的時候,需要記憶體,這個時候作業系統才真正分配記憶體,這樣就會加大young gc的停頓時間;
2、可能存在記憶體碎片的問題。
可以在JVM啟動的時候,配置
-XX:+AlwaysPreTouch複製程式碼
引數,這樣JVM就會先訪問所有分配給它的記憶體,讓作業系統把記憶體真正的分配給JVM.後續JVM就可以順暢的訪問記憶體了。
GC引數
JAVA 1.7用的垃圾收集演算法還是CMS,下文提到的引數都是針對CMS的。
CMSInitiatingOccupancyFraction
之前寫過一篇java垃圾回收演算法之-CMS(併發標記清除),裡面提到垃圾收集執行緒會跟應用的執行緒一起並行的工作,萬一垃圾收集執行緒在工作的時候,老年代記憶體不足怎麼辦?因此最好還是提前啟動CMS來收集垃圾(CMS GC)。
可以通過設定
CMSInitiatingOccupancyFraction=75複製程式碼
那麼當老年代堆空間的使用率達到75%的時候就開始執行垃圾回收,CMSInitiatingOccupancyFraction預設值是92%,這個就太大了。
CMSInitiatingOccupancyFraction引數必須跟下面兩個引數一起使用才能生效的。
-XX:+UseConcMarkSweepGC
-XX:+UseCMSInitiatingOccupancyOnly複製程式碼
MaxTenuringThreshold
新生代是使用copy演算法來進行垃圾回收的,可以參看
預設情況下,當新生代執行了15次young gc後,如果還有物件存活在Survivor區中,那麼就可以直接將這些物件晉升到老年代,但是由於新生代使用copy演算法,如果Survivor區存活的物件太久的話,Survivor區存活的物件就越多,這個就會影響copy演算法的效能,使得young gc停頓的時間加長,建議設定成6。
-XX:MaxTenuringThreshold=6複製程式碼
ExplicitGCInvokesConcurrent
如果系統使用堆外記憶體,比如用到了Netty的DirectByteBuffer類,那麼當想回收堆外記憶體的時候,需要呼叫
System.gc()複製程式碼
而這個方法將進行full gc,整個應用將會停頓,如果是使用CMS垃圾收集器,那麼可以設定
-XX:+ExplicitGCInvokesConcurrent複製程式碼
這個引數來改變System.gc()
的行為,讓其從full gc –> CMS GC,CMS GC是併發收集的,且中間執行的過程中,只有部分階段需要stop the world。
注意:設定了ExplicitGCInvokesConcurrent,那就不要設定DisableExplicitGC引數來禁掉System.gc()
。
記憶體引數
-Xmx, -Xms
這兩個一般都是設定4個g
NewRatio
GC最多的還是發生在新生代的young gc,所以可以提高一下新生代在整個堆的佔用比例,建議設定為對半分,儘量避免young gc
-XX:NewRatio=1複製程式碼
原文連結