1. 程式人生 > >JVM調優系列:(五)JVM常用除錯引數和工具

JVM調優系列:(五)JVM常用除錯引數和工具

JVM常用除錯引數:

–verbose:gc在虛擬機發生記憶體回收時在輸出裝置顯示資訊

-Xloggc:filename把GC相關日誌資訊記錄到檔案以便分析

-XX:-HeapDumpOnOutOfMemoryError當首次遭遇OOM時匯出此時堆中相關資訊

-XX:OnError="<cmdargs>;<cmd args>" 出現致命ERROR之後執行自定義命令

-XX:-PrintClassHistogram遇到Ctrl-Break後列印類例項的柱狀資訊,與jmap -histo功能相同

-XX:-PrintConcurrentLocks遇到Ctrl-Break後列印併發鎖的相關資訊,與jstack -l功能相同

-XX:-PrintGC每次GC時列印相關資訊

-XX:-PrintGCDetails每次GC時列印詳細資訊

-XX:-PrintGCTimeStamps列印每次GC的時間戳

-XX:+PrintGCApplicationStoppedTime列印垃圾回收期間程式暫停的時間

-XX:+PrintHeapAtGC列印GC前後的詳細堆疊資訊

-XX:+PrintTenuringDistribution檢視每次minor GC後新的存活週期的閾值,即在年輕代survivor中的複製次數.

-XX:-TraceClassLoading跟蹤類的載入資訊

-XX:-TraceClassUnloading跟蹤類的解除安裝資訊

-XX:-TraceLoaderConstraints跟蹤類載入器約束的相關資訊

-XX:ErrorFile=/opt/tomcat/bin/hs_error_%p.log  Crash日誌

[GC [DefNew:209792K->4417K(235968K), 0.0201630 secs] 246722K->41347K(498112K),0.0204050 secs]

YoungGen記憶體區回收前209792K,回收後4417K, YoungGen大小是235968K, HEAP 記憶體區回收前246722K, 回收後41347K, heap的大小是498112K,GC消耗的時間是0.0204050 secs

 [GC [1 CMS-initial-mark: 655374K(1310720K)] 662197K(1546688K), 0.0303050 secs] [Times: user=0.02 sys=0.02, real=0.03 secs]

 [weak refs processing, 0.0417710 secs] [1 CMS-remark: 655734K(1310720K)] 766736K(1546688K), 0.0932010 secs] [Times: user=0.17 sys=0.00, real=0.09 secs]

CMS-initial-mark階段暫停了0.0303050秒,而CMS-remark階段暫停了0.0932010秒,因此兩次暫停的總共時間是0.123506秒.

兩種fail引起full gc:Prommotionfailed和Concurrent mode failed:

[ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]

 [CMS: 1458785K->1120688K(2520704K), 9.4584090 secs]

Prommotion failed由於救助空間不夠,從而向年老代轉移物件,年老代沒有足夠的空間來容納這些物件; 或者老生代空閒空間存在碎片,導致沒有足夠大的連續空間開存放新生代對,導致一次fullgc的產生。解決這個問題的辦法有兩種完全相反的傾向:增大救助空間、增大年老代。調整-XX:SurvivorRatio引數

Concurrent mode failed的產生是由於CMS回收年老代的速度太慢,導致年老代在CMS完成前就被沾滿,引起full gc,避免這個現象的產生就是調小-XX:CMSInitiatingOccupancyFraction引數的值.

java.lang.OutOfMemoryError:GC overhead limit exceeded:

JDK6新添的錯誤型別。是發生在GC佔用大量時間為釋放很小空間的時候發生的,是一種保護機制。解決方案是,關閉該功能,使用-XX:-UseGCOverheadLimit. 需要檢視是否有使用大記憶體的程式碼或死迴圈。

JVM常用除錯工具:

jconsole – jconsole是基於JavaManagementExtensions (JMX)的實時圖形化監測工具,這個工具利用了內建到JVM裡面的JMX指令來提供實時的效能和資源的監控,包括了Java程式的記憶體使用,Heap size, 執行緒的狀態,類的分配狀態和空間使用等等。Linux下設定環境變數如下:export DISPLAY=:0.0

啟動jvm監控服務。它是一個基於rmi的應用,向遠端機器提供本機jvm應用程式的資訊。預設埠1099。

-nr 當一個存在的RMI Registry沒有找到時,不嘗試建立一個內部的RMI Registry

-p port 埠號,預設為1099

-nrminame 預設為JStatRemoteHost;如果多個jstatd服務開始在同一臺主機上,rminame唯一確定一個jstatd服務

-J jvm選項

$JAVA_HOME/jre/lib/security/java.policy檔案中新增下面的程式碼:

grantcodebase "file:${java.home}/../lib/tools.jar" {

  permission java.security.AllPermission;

};

預設埠為1099:   jstatd -J-Djava.security.policy=jstatd.all.policy

指定hostname 指定埠: jstatd -J-Djava.rmi.server.hostname=192.168.8.7-J-Djava.security.policy=test/jstatd.all.policy -p 6001  

 啟動JMX: jstatd -J-Djava.rmi.server.hostname=192.168.8.7-J-Djava.security.policy=test/jstatd.all.policy  -J-Dcom.sun.management.jmxremote.port=6001 -J-Dcom.sun.management.jmxremote.ssl=false-J-Dcom.sun.management.jmxremote.authenticate=false -J -Djava.awt.headless=true

(java.net.MalformedURLException:Local host name unknown: java.net.UnknownHostException: a: a

原因是/etc/hosts檔案裡沒有主機名為:a的,解決方法就是在hosts檔案中加入a:

127.0.0.1   a   localhost)

jps –jps是用來檢視JVM裡面所有程序的具體狀態, 包括程序ID,程序啟動的路徑等等。

-m 輸出傳遞給main方法的引數,如果是內嵌的JVM則輸出為null。

-l 輸出應用程式主類的完整包名,或者是應用程式JAR檔案的完整路徑。

-v 輸出傳給JVM的引數。

jstack -- jstack用於打印出給定的java程序ID或core file或遠端除錯服務的Java堆疊資訊,如果是在64位機器上,需要指定選項"-J-d64",如果java程式崩潰生成core檔案,jstack工具可以用來獲得core檔案的java stack和nativestack的資訊。Windows的jstack只支援-l.

-F當’jstack [-l] pid’沒有相應的時候強制列印棧資訊

-l長列表. 列印關於鎖的附加資訊,如屬於java.util.concurrent的ownable synchronizers列表.

-m列印java和native c/c++框架的所有棧資訊.

Jstackpid  顯示jvm中當前所有執行緒的執行情況和執行緒當前狀態

jinfo –可以輸出並修改執行時的java 程序的opts。用處比較簡單,用於輸出JAVA系統引數及命令列引數。檢視和修改執行中的java程式的執行環境引數。

jinfo-flag MaxPermSize  4084

jmap –jmap 可以從core檔案或程序中獲得記憶體的具體匹配情況,包括Heap size, Perm size等等,打印出某個java程序(使用pid)記憶體內的,所有‘物件’的情況。

-heap :列印jvm heap的情況
-histo: 列印jvm heap的直方圖。其輸出資訊包括類名,物件數量,物件佔用大小。
-histo:live : 同上,但是隻輸出存活物件的情況,會觸發FULL GC

-permstat: 列印permanentgeneration heap情況

jmap-dump:format=b,file=outfile 3024可以將3024程序的記憶體heap輸出出來到outfile檔案裡,再配合JHAT進行分析.

Jhat用於對JAVA heap進行離線分析的工具,他可以對不同虛擬機器中匯出的heap資訊檔案進行分析,如LINUX上匯出的檔案可以拿到WINDOWS上進行分析

jhat -J-Xmx512m <heap dump file>

jstat – jstat利用了JVM內建的指令對Java應用程式的資源和效能進行實時的命令列的監控, 可以觀察到classloader,compiler,gc相關資訊,包括了對Heap size和垃圾回收狀況的監控等等。

-class:統計class loader行為資訊
-compile:統計編譯行為資訊
-gc:統計jdk gc時heap資訊
-gccapacity:統計不同的generations(不知道怎麼翻譯好,包括新生區,老年區,permanent區)相應的heap容量情況
-gccause:統計gc的情況,(同-gcutil)和引起gc的事件
-gcnew:統計gc時,新生代的情況
-gcnewcapacity:統計gc時,新生代heap容量
-gcold:統計gc時,老年區的情況
-gcoldcapacity:統計gc時,老年區heap容量
-gcpermcapacity:統計gc時,permanent區heap容量
-gcutil:統計gc時,heap情況

-compiler:顯示VM實時編譯的數量等資訊

-snap: 檢視Java程序的jvmstat的各個monitor的值

java-verbose:class PID輸出虛擬機器裝入的類的資訊, 當虛擬機器報告類找不到或類衝突時可用此引數來診斷來檢視虛擬機器從裝入類的情況。

java –verbose:jni輸出native方法呼叫的相關情況,一般用於診斷jni呼叫錯誤資訊

常用JVM分析資訊獲取:

1、確認伺服器上是否存在SUN JDK6,如果沒有建議安裝一個,我們需要使用裡面的工具(jps、jmap、jstat、jconsole、jstack)

2、 獲取MKEY的JAVA程序ID(後面簡稱PID)

a)   操作方法:進入SUN JDK的bin目錄在命令列中輸入jps,檢視MKEY的程序ID

3、提取GC資訊()

a)   操作方法:示例:jstat –gcPID 600000 43200 >> gc_20110909.log

4、 提取Heap區資訊(間隔10分鐘提取一次)

a)   操作方法:jmap -heap PID >>heap_20110909.log

5、提取物件資訊(間隔10分鐘提取一次)

a)      操作方法:jmap-histo PID > histo_*.log(檔案較大,*按序號生成輸入)

6、執行緒轉儲日誌

a)      jstack PID

b)      宕機日誌(在domain目錄,如果沒有宕機,條件允許的情況下可使用 kill -3 PID(此操作會殺掉程序))

精簡版:

伺服器掛起後,在重啟之前執行以下命令:

jps-vl 查詢到相應的JAVA程序,簡稱PID

jstat –gcutilPID 5000 >> /opt/tomcat/bin/gcutil.log

vmstat3

jstackPID > /opt/tomcat/bin/jstack.log

jmap-histo PID > /opt/tomcat/bin/histo.log

網路方面:

whiletrue; do A=$(netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a,S[a]}'); echo $A ; sleep 3; done

netstat -an | grep1521

再重啟服務.提取相關日誌發出來