1. 程式人生 > >JAVA效能優化—IBM JDK JVM引數設定

JAVA效能優化—IBM JDK JVM引數設定

本文將描述IBM JDK下常用引數的設定。  -Xms:最小堆大小 
  -Xmx:最大堆大小 
  -Xminf and -Xmaxf:GC(垃圾回收)之後可用空間的最小值最大值 
  -Xmine and -Xmaxe:堆增長的最小最大值 
  -Xmint and -Xmaxt:垃圾回收佔時間整個執行時間的比例,預設是5%。如果回收時間小於5%,那麼它就縮減堆,反之增大。 
  一般來說只要對Xms和Xmx設定合理,後面的三對不用特別設定。可以看看http://publib.boulder.ibm.com/infocenter/javasdk/v5r0/index.jsp上heap expasion和heap shrinkage兩章的說明,除非有下文的情況: 
  如果使用大小可變的堆(比如,-Xms 和 -Xmx 不同),應用程式可能遇到這樣的情況,不斷出現分配失敗而堆沒有擴充套件。這就是堆失效,是由於堆的大小剛剛能夠避免擴充套件但又不足以解決以後的分配失敗而造成的。通常,垃圾收集週期釋放的空間不僅可以滿足當前的分配失敗,而且還有很多可供以後的分配請求使用的空間。但是,如果堆處於失效狀態,那麼每個垃圾收集週期釋放的空間剛剛能夠滿足當前的分配失敗。結果,下一次分配請求時,又會進入垃圾收集週期,依此類推。大量生存時間很短的物件也可能造成這種現象。避免這種迴圈的一種辦法是增加 -Xminf 和 -Xmaxf 的值。比方說,如果使用 -Xminf.5,堆將增長到至少有 50% 的自由空間。同樣,增加 -Xmaxf 也是很合理。如果 -Xminf等於0.5,-Xmaxf 為預設值 0.6,因為 JVM 要把自由空間比例保持在 50% 和 60% 之間,所以就會出現太多的擴充套件和收縮。兩者相差 0.3 是一個不錯的選擇,這樣 -Xmaxf.8 可以很好地匹配 -Xminf.5。如果記錄表明,需要多次擴展才能達到穩定的堆大小,但可以更改 -Xmine,根據應用程式的行為來設定擴充套件大小的最小值。目標是獲得足夠的可用空間,不僅能滿足當前的請求,而且能滿足以後的很多請求,從而避免過多的垃圾收集週期。-Xmine、-Xmaxf 和 -Xminf 為控制應用程式的

記憶體使用特性提供了很大的靈活性。 
  摘自Java效能優化的策略和常見方法 
  所以在應用正式上線的頭一段時間,最好把GC日誌開啟,觀察一下堆(heap)的增長(expasion)和收縮(shrinkage)。最佳的情況就是,每次回收後可用的堆大小佔整個堆的50%左右。如果回收後才騰出30%不到的可用空間,那就該再調整一下上述的引數了。下圖看起來直觀一點,使用-verbose:size引數可以檢視當前的預設值。 


  那為何不把Xms和Xmx設定成一樣大,就像SUN的JDK所推薦的那樣? 
  Using the same values is not usually a good idea, because it delays the start of garbage collection until the heap is full. The first time that the Garbage Collector runs, therefore, becomes a very expensive operation. Also, the heap is more likely to be fragmented and require a heap compaction. Again this is a very expensive operation.…… 
  If the Garbage Collector cannot find enough garbage, it runs compaction. If the Garbage Collector finds enough garbage, or any of the other conditions for heap expansion are met , the Garbage Collector expands the heap. 
  因為IBM JDK採用的是標記(mark)-掃描(sweep)-標記-……-掃描-緊湊排列(compact),如果還不能提供足夠的空間,擴充套件堆(expasion)。依次迴圈,直到達到最大堆大小。每次擴充套件前,那些長存的物件就被調整到堆的底部,每次擴充套件後需要再動的量就很少。所以如果把Xms設定成和Xmx一樣,那麼掃描和緊湊排列這麼一個充滿
記憶體
碎片的大堆的開銷將大大高於從小擴充套件堆的開銷。 
  The overheads of expanding the heap are almost trivial compared to the cost of collecting and compacting a very large fragmented heap. 
  這是由於IBM的GC特點造成的,而SUN的JDK採用的是分代回收的策略,所以就沒有這種情況,反而會受益於堆大小一致。不過這麼說起來,用了-Xgcpolicy:gencon,就應該把最小堆最大堆設定成一樣咯。 
  在Gencon回收策略下,可以通過-Xmn來設定嬰兒區域(Nursery或者叫young)的大小,通過-Xmo來設定長存區(tenured或者old)的大小。注意-Xmn不能和-Xmns/-Xmnx引數一起使用,-Xmo不能和-Xmos/-Xmox一起使用,否則會報錯。前者就是把年輕代和長存代的大小固定了,而後兩者就是設定兩個部分最大最小的範圍,預設情況下: 
  -Xmns是-Xms的25%或者64M(在JDK 5.0中預設是25%) 
  -Xmnx是-Xmx的25%或者64M(同上) 
  -Xmos是-Xmx減去-Xmns的大小 
  -Xmox是和-Xmx一樣大 
  可見預設的年輕代太小了,生產環境中有必要改大一點。
因為年輕代使用的是複製策略,所以回收速度相當快(minor gc),而長存代使用的是和optavgpause 策略相似的方式進行併發標誌、掃描策略,回收速度比較慢(major gc)。理想情況是minor gc和major gc的比值在1:1010:1左右。(可以通過GC日誌查看回收的區域) 
  gencon中年老期限(Tenure age)和傾斜比率(Tilt ratio)這兩個引數是JVM自己動態調整的。 
  針對固定物件問題(Pinned Objects),使用-Xk -Xp引數設定kCluster和pCluster,Avoiding Java heap fragmentation with Java SDK V1.4.2. 或者我這篇IBM JDK的Java堆空間的碎片問題。 
  一些不常用的引數: 
  -Xloainitial<percentage> -Xloamaximum<percentage> :調整大物件區域(Large Object Area)的大小。分配總是先在SOA(Small Object Area)中分配,如果沒有空間並且需要分配的大小大於64K,那麼分配到LOA。預設情況下為-Xloainitial0.05 (5%),-Xloamaximum0.5 (50%),如果你的程式確實需要分配許多大物件的話(大於64K),那麼可以調整LOA的初始百分比。 
  以上兩點可以參考我這篇IBM JDK的Java堆空間的碎片問題,獲得更詳細的解釋。 
  總結一下來說,對於optthruput和optavgpause,設定恰當的最大堆和最小堆,設定-Xk和-Xp避免碎片問題,如果程式需要分配大物件較多,那麼調整一下LOA的大小;對於gencon,可以調大最小堆和最大堆接近,調整young區域的大小,LOA也可以視情況調整。subpool一般用不到,就不去研究了。 
  一些另外的資訊 
  Default settings for the JVM 
  http://publib.boulder.ibm.com/infocenter/javasdk/v5r0/index.jsp?topic=/com.ibm.java.doc.diagnostics.50/diag/appendixes/defaults.html 
  JVM environment settings 
  http://publib.boulder.ibm.com/infocenter/javasdk/v5r0/index.jsp?topic=/com.ibm.java.doc.diagnostics.50/diag/appendixes/env_var/env_jvm.html 
  預設的Heapdumps是關閉的,除錯的時候記得開啟;預設的Javadumps on out of memory和Heapdumps on out of memory都是開啟的,但是預設的dump位置是profile的所在目錄,最好在管理控制檯java程序中把IBM_HEAPDUMPDIR和IBM_JAVACOREDIR設定到別的目錄,防止dump內容把WAS的檔案系統撐爆,影響正常業務使用。 
  在Windows機器上,如果記憶體大於4G,記得開啟/3GB引數,這樣可以使JVM Heap可以設定的更大一些,接近2G-1,(其它的三部分可以擴充套件到另外的1G上去),但一般最大不超過1.7G。