標籤:jconsole jmap jvm調優 java虛擬機器 記憶體調優
1. 前言
- 想驗證你對 jvm 配的一些調優參數(比如 Xms、Xmx 等)有沒有起作用嗎?
- 想不想即時監控你自訂的線程池的在實際運行時的線程個數、有沒有死結?
- 應用出現 java.lang.OutOfMemoryError: Java heap space,你知道需要去調整 Xms、Xmx。想不想即時監控你的 Java 應用的堆記憶體使用量情況,並根據峰值等資料設定最適合你的 Xms、Xmx 等參數?
- 應用出現 java.lang.OutOfMemoryError: PermGen space,你知道需要去調整 XX:PermSize、XX:MaxPermSize。想不想找到你的應用的永久區 PermGen 的使用峰值,並根據其去設定合理的 XX:PermSize、XX:MaxPermSize 等參數?
- 我們都知道,JVM 堆記憶體劃分為年輕代和年老代。JVM 年老代與年輕代的比例(即 XX:NewRatio,這個名字容易讓人產生混淆,即認為是年輕代比年老代)為 2(即把 JVM 堆記憶體平均分成了三份,年老大佔用了兩份,而年輕代佔用一份。參考資料 Sun Java System Application Server Enterprise Edition 8.2 Performance Tuning Guide),這個比例並不適合所有情況,特別是當你的應用裡局部變數遠遠大於全域變數,而且大量局部變數生命週期都很短的時候。如何根據應用即時的運行運行情況合理配置年輕代(Young Generation,即 Eden 區和兩個 Survivor 區之和)和年老代(Old Generation,即 Tenured 區)的比例 XX:NewRatio 值?
Java 內建效能監控工具:監視和管理主控台 jconsole,它可以提供 Java 某個進程的記憶體、線程、類載入、jvm 概要以及 MBean 等的即時資訊,也許能夠對以上問題提供參考。
2. JVM 一些參數在啟動 jconsole 之前我們先來回顧一下 JVM 的一些主要參數:
- -Xms 初始/最小堆記憶體大小
- -Xmx 最大堆記憶體大小
- -Xmn 年輕代大小
- -XX:NewSize 年輕代大小
- -XX:MaxNewSize 年輕代最大值
- -XX:NewRatio 年老代與年輕代比值
- -XX:MaxPermSize 持久代最大值
- -XX:PermSize 持久代初始值
有些資料說,Xms、Xmx 設定的是 JVM 記憶體大小,是不對的,JVM 除了留給開發人員使用的堆記憶體之外還有非堆記憶體。
讀者可能發現,有三種方式可以劃分年輕代大小:-Xmn 方式、-XX:NewSize + -XX:MaxNewSize 方式、-XX:NewRatio 方式。三種都可以,優先順序從高到低依次是 -XX:NewSize + -XX:MaxNewSize 方式、-Xmn 方式、-XX:NewRatio 方式,也就是說配置了前面優先順序高的後面的就被覆蓋掉了。
3. 本機啟用 jconsole 以監控 Java 進程CMD 切換到 %JAVA_HOME%/bin 目錄,直接執行 jconsole
即可開啟 Java 監視和管理主控台:
本地進程列表裡顯示了所有本地執行中的 Java 進程,雙擊你感興趣的那個進程(比如 PID 為 8504 那個),即可對該進程進行監控了:
4. 遠程監控 Java 進程要對 Java 進程進行遠程監控,在啟動它的時候需要啟用 JMX。
以遠程主機上的 tomcat 為例,先為 jmx 找一個可用的遠程連接埠,比如 9999:
No news is good news~在 %TOMCAT_HOME%/bin/catalina.sh 檔案的前面加上以下配置:
JAVA_OPTS="-Xms1024m -Xmx2048m -XX:MaxPermSize=128m -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
然後重啟 tomcat,在本機開啟 Java 監視和管理主控台,"遠程進程" 輸入遠程主機名稱和 jmx 連接埠號碼:
點擊 "串連" 按鈕,即可對遠程主機上的 tomcat 進行即時監控了:
5. jconsole 提供的一些有用資訊接著第 4 步的案例往下看。
5.1. JVM 設定資訊是否起作用檢查點擊 "VM 概要" 可以查看到剛才我們設定的 JAVA_OPTS 的一些參數已經奏效了:
5.2. tomcat 線程池、自訂線程池數量情況即時監控還在為 tomcat 線程池的神秘面紗而頭疼?還在為自己定義的線程池 "黑盒" 一般而苦惱?看看:
我們的 tomcat 剛啟動,從可以看出只有一個 http-8080-Acceptor-0 線程,我們去訪問一下我們的項目,然後再回來看看:
http-8080 線程一下子增長到了 8 個。是不是一切一目瞭然,盡在掌握之中?
5.3. 記憶體使用量實際消耗點擊 Java 監視和管理主控台 "記憶體" 葉項,可以看到 tomcat 堆記憶體的使用方式:
圖表裡有很多選項:
我們看一下 Eden 區:
Eden 區基本和整個堆記憶體的走勢差不多。再看 Survivor 區:
Survivor 區在較短時間內的走勢相對平穩。再看 Old Gen 區:
這個走勢更加平穩,而且對比 Survivor 區、Old Gen 區兩張圖,可以很明顯地看出,在大約 19:58 那個時刻有將一批對象從 Survivor 區移到 Old Gen 區。最後看 Perm Gen 區。
這個走勢最平穩了。可以明顯看出,在大約 19:58,在我們訪問一下我們的項目的時候,一些新的 class 等靜態資源載入到了 JVM 中。5.4 的載入類數的圖也證實了這一點。
5.4. tomcat 載入類的情況
6. 配合 jmap 的使用
先找到我們 tomcat 進程的 PID 是 13863,然後執行 jmap -heap 13863:
Heap Configuration 裡列的基本就是我們剛才配的那些,比如 MaxHeapSize 是 2048 MB,MaxPermSize 是 128 MB。這個和 5.1 裡的是一樣的。
參考資料
- Sun Java System Application Server Enterprise Edition 8.2 Performance Tuning Guide
- Frequently Asked Questions About the Java HotSpot VM
Java 內建效能監控工具:監視和管理主控台 jconsole 的使用