微信公衆號【Java技術江湖】一位阿里 Java 工程師的技術小站。做者黃小斜,專一 Java 相關技術:SSM、SpringBoot、MySQL、分佈式、中間件、集羣、Linux、網絡、多線程,偶爾講點Docker、ELK,同時也分享技術乾貨和學習經驗,致力於Java全棧開發!(關注公衆號後回覆」Java「便可領取 Java基礎、進階、項目和架構師等免費學習資料,更有數據庫、分佈式、微服務等熱門技術學習視頻,內容豐富,兼顧原理和實踐,另外也將贈送做者原創的Java學習指南、Java程序員面試指南等乾貨資源)
VisualVM是一款免費的JAVA虛擬機圖形化監控分析工具。html
1. 擁有圖形化的監控界面。
2. 提供本地、遠程的JVM監控分析功能。
3. 是一款免費的JAVA工具。
4. VisualVM擁有豐富的插件支持。java
VisualVM官方網站:http://visualvm.java.net/程序員
VisualVM各版本下載頁面: http://visualvm.java.net/releases.html面試
下載VisualVM時也應該注意,不一樣的JDK版本對應不一樣版本的VisualVM,具體根據安裝的JDK版原本下載第一的VisualVM。數據庫
下載版本參考:[](http://blog.csdn.net/chwshuan...Java虛擬機性能管理神器 - VisualVM(4) - JDK版本與VisualVM版本對應關係安全
備註:下列表中顯示1.3.6版本只適合JDK7和JDK8,但是我用1.3.6版仍是能夠監控JDK1.6_45的版本。性能優化
顯示JAVA應用程序JVM參數,系統屬性,JVM的信息和運行環境。服務器
能夠鏈接到遠程服務器上運行的JAVA應用程序,監控應用程序的運行狀態。微信
能夠監控到應用程序熱點方法的執行單次時間、總耗時、耗時佔比。網絡
顯示應用程序在運行時的編譯時間、加載時間、垃圾回收時間、內存區域的回收狀態等。
監控應用程序線程的運行、休眠、等待、鎖定狀態。
顯示線程當前運行狀態和關聯類信息。
另外還提供更多更強大、方便的第三方插件。
Java虛擬機性能管理神器 - VisualVM(2) 監控遠程主機上的JAVA應用程序
使用VisualVM監控遠程主機上JAVA應用程序時,須要開啓遠程主機上的遠程監控訪問,或者在遠程JAVA應用程序啓動時,開啓遠程監控選項,兩種方法,選擇其中一種就能夠開啓遠程監控功能,配置完成後就能夠在本地對遠程主機上的JAVA應用程序進行監控。
在JAVA_HOME/bin目錄中,建立名稱爲jstatdAllPolicy文件(這個文件名稱也能夠順便起,不過要與jstatd啓動時指定名稱相同),將如下內容拷貝到文件中。並保證文件的權限和用戶都正確。
grant codebase"file:${java.home}/../lib/tools.jar"{ permission java.security.AllPermission; };
在JAVA_HOME/bin目錄中,執行如下命令:
./jstatd -J-Djava.security.policy=jstatdAllPolicy-p 1099 -J-Djava.rmi.server.hostname=192.168.xxx.xxx
jstatd命令描述以及參數說明:
jstatd是一個基於RMI(Remove Method Invocation)的服務程序,它用於監控基於HotSpot的JVM中資源的建立及銷燬,而且提供了一個遠程接口容許遠程的監控工具鏈接到本地的JVM執行命令。
-J-Djava.security.policy=jstatdAllPolicy 指定安全策略文件名稱
-p 1099 指定啓動端口
-J-Djava.rmi.server.hostname=192.168.xxx.xxx 指定本機IP地址,在hosts文件配置不正常時使用,最好加上。
在須要遠程監控的JVM啓動時,開啓遠程監控選項
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=192.168.xxx.xxx
在本地VisualVM的應用程序窗口,右鍵單擊【遠程】》【添加遠程主機】》【主機名】中輸入遠程主機的IP地址,點擊【高級設置】輸入遠程主機開啓的監控端口,點擊【肯定】完成配置。
若是一切正常,就能夠看到遠程主機上的JAVA應用程序了。
Java虛擬機性能管理神器 - VisualVM(3) 排查JAVA應用程序內存泄漏
線上應用部署完成後,運行1~2天左右就會出現假死,或者某天早上8~10點高峯期間忽然不處理數據了。因爲在測試環境的壓力測試沒有作徹底,也沒有遇到相關問題。狀況出現後對客戶的使用形成很大影響,領導要求趕忙排查出問題緣由!
排查緣由前,與運維溝通,瞭解線上服務器的運行狀態,經過ganglila觀察網絡、CPU、內存、磁盤的運行歷史狀態,發現程序故障前,都有一波很高的負載,排查線上日誌,負載來源在8~9點平臺接入數據量成倍增長,經過與產品和市場人員分析,此時段是用戶集中上班、接入平臺的高峯時段,訪問日誌也顯示,業務場景正常,無網絡攻擊和安全問題。屬於產品業務正常的場景。
排除了網絡安全因素後,就從程序的運行內部進行排查,首先想到的獲取JVM的dmp文件。獲取JVM的dmp文件有兩中方式:
1. JVM啓動時增長兩個參數,出現 OOME 時生成堆 dump:
-XX:+HeapDumpOnOutOfMemoryError
生成堆文件地址:
-XX:HeapDumpPath=/home/test/jvmlogs/
2. 發現程序異常前經過執行指令,直接生成當前JVM的dmp文件,15434是指JVM的進程號
jmap -dump:format=b,file=serviceDump.dat 15434
因爲第一種方式是一種過後方式,須要等待當前JVM出現問題後才能生成dmp文件,實時性不高,第二種方式在執行時,JVM是暫停服務的,因此對線上的運行會產生影響。因此建議第一種方式。
獲取到dmp文件後,就開始進行分析。將服務器上的dmp文件拷貝到本地,而後啓動本地的VisualVM,點擊菜單欄【文件】選項,裝入dmp文件
打開dmp文件後,查看類標籤,就能看到佔用內存的一個排行。
而後經過檢查中查找最大的對象,排查到具體線程和對象。
上列中的com.ctfo.trackservice.handler.TrackHandleThread#4就是重點排查對象。
經過代碼的比對,在此線程中,有調用DAO接口,負責將數據存儲到數據庫中。而存儲到數據庫中時,因爲存儲速度較慢,致使此線程中的數據隊列滿了,數據積壓,沒法回收致使了隊列鎖定,結果就是程序假死,不處理數據。
經過進一步分析,發現數據庫存儲時有瓶頸,雖然當前是批量提交,速度也不快。平均8000/秒的存儲速度。而數據庫有一個DG(備份)節點,採用的是同步備份方式,即主庫事務要等DG的事務也完成後才能返回成功,這樣就會由於網絡因素、DG性能因素等緣由致使性能降低。經過與DBA、產品、溝通,將同步備份改成異步備份,實時同步改成異步(異步可能會致使主備有10分鐘之內的數據延遲)。速度達到30000/秒。問題解決。
至此,經過VisualVM分析java程序內存泄漏到此結束。不過還有幾個問題:1. 若是dmp文件較大,VisualVM分析時間可能好久;另外,VisualVM對堆的分析顯示功能還不算全面。若是須要更全面的顯示,就可使用另一個專業的dmp文件分析工具【Memory Analyzer (MAT)】,此工具能夠做爲eclipse的插件進行安裝,也能夠單獨下載使用。若是有感興趣的朋友,我我的建議仍是單獨下載使用。下載地址:http://www.eclipse.org/mat/
Java虛擬機性能管理神器 - VisualVM(4) 查找JAVA應用程序耗時的方法函數
JAVA程序在開發前,根據設計文檔的性能需求,是要對程序的性能指標進行測試的。好比接口每秒響應次數要求1000次/秒,就須要平均每次請求處理的時間在1ms之內,若是須要知足這個指標,就須要在開發階段對接口執行函數進行監控,也能夠經過打印日誌進行監控,從而統計對應的性能指標,而後能夠根據性能指標的要求進行相應優化。
根據具體業務的場景和需求,主要集中在IO通信、文件讀寫、數據庫操做、業務邏輯處理上,這些都是制約性能的重要因素,因此須要重點關注。
在研發環境,大部分會使用syso的方式或者日誌方式打印性能損耗,若是代碼沒有加在運行時纔想起來,或者想關注忽然想起的函數,換作之前,是須要重啓服務的,若是有VisualVM就能夠直接查看耗時以及調用次數等狀況。而不用打印、輸出日誌來查看性能損耗。
對於性能損耗的函數,根據業務邏輯能夠進行相應的優化,例如字符串處理、文件讀寫方式、SQL語句優化、多線程處理等等方式。
因爲性能優化涉及的內容不少,這裏就不深刻了。主要是告訴你們經過VisualVM來排查問題的具體位置。
Java虛擬機性能管理神器 - VisualVM(5) 排查JAVA應用程序線程鎖
JAVA線程鎖的例子和緣由網上一大堆,我也不在這裏深刻說明,這裏主要是否講如何使用VisualVM進行排查。至於例子能夠看這裏:http://blog.csdn.net/fengzhe0411/article/details/6953370
這個例子比較極端,通常狀況下,出現鎖競爭激烈是比較常見的。
啓動 VisualVM,在應用程序窗口,選擇對應的JAVA應用,在詳情窗口》線程標籤(勾選線程可視化),查看線程生命週期狀態,主要留意線程生命週期中紅色部分。
(1)綠色:表明運行狀態。通常屬於正常狀況。若是是多線程環境,生產者消費者模式下,消費者一直處於運行狀態,說明消費者處理性能低,跟不上生產者的節奏,須要優化對應的代碼,若是不處理,就可能致使消費者隊列阻塞的現象。對應線程的【RUNNABLE】狀態。
(2)藍色:表明線程休眠。線程中調用Thread.sleep()函數的線程狀態時,就是藍色。對應線程的【TIMED_WAITING】狀態。
(3)黃色:表明線程等待。調用線程的wait()函數就會出現黃色狀態。對應線程的【WAITING】狀態。
(4)紅色:代碼線程鎖定。對應線程的【BLOCKED】狀態。
發生線程鎖的緣由有不少,我所遇到比較多的狀況是多線程同時訪問同一資源,且此資源使用synchronized關鍵字,致使一個線程要等另一個線程使用完資源後才能運行。例如再沒有鏈接池的狀況下,同時訪問數據庫接口。這種狀況會致使性能的極具降低,解決的方案是增長鏈接池,或者修改訪問方式。或者將資源粒度細化,相似ConCurrentHashMap中的處理方式,將資源分爲多個更小粒度的資源,在更小粒度資源上來處理鎖,就能夠解決資源競爭激烈的問題。]