Java性能問題定位 原

一句話總結:從問題現象爲入口,歸結爲3類問題進行定位分析:內存滿、CPU高、線程阻塞。

首先先介紹下jvisualvm這款jdk自帶的性能工具。通常我們要定位哪塊代碼性能差,耗時久,最原始的辦法就是在各個方法前後日誌打印時間戳並計算耗時,這種方法很繁瑣,通常要加很多日誌多次部署才能定位到,我一開始也是這麼搞的。而使用jvisualvm工具則可以直接查看整個業務代碼調用鏈中各個方法的耗時及佔比,直接就能定界出是哪個方法性能差,耗時久。

操作步驟:點擊抽樣器頁籤,點擊CPU抽樣,前臺操作觸發代碼執行,操作完點擊停止,再點擊快照。在快照頁點擊搜索按鈕,輸入代碼入口方法名搜索,結果見下圖。

我們來分析下下圖,RegionNorthbound.createRegion是北向入口方法,總耗時見右側5.298秒,其調用了RegionServiceImpl.createRegion方法,耗時4.093秒,那麼相減就是RegionNorthbound.createRegion方法本身的耗時。

RegionServiceImpl.createRegion方法調用了CommonDao.saveEntity和RegionServiceImpl.checkRepeat方法,分別耗時0.998秒和0.094秒。可以直觀查看是調用的哪個方法耗時久,性能差。整個方法調用鏈的耗時均可查看。

這在大型系統中非常有用。大型系統中通常業務由業務部門開發,平臺由平臺部門開發,只提供jar包給業務部門使用。那麼當測試出性能問題時,首先要定界出是業務的問題還是平臺的問題,再轉給對應部門去修改。業務開發不知道平臺的實現,無法查看修改其代碼,更不用說去加日誌。固通過此工具可以快速定界出問題責任主體。

 

當然jvisualvm除了查看代碼調用鏈耗時,實時監控CPU、內存、線程數,線程dump、內存dump等功能都非常好用。

 

下面開始按問題分類進行定位分析。

一:內存問題

問題現象:後臺報錯,前臺提示異常或500錯誤。

定位:後臺報錯的定位思路很明確了,查看日誌,這裏分兩類異常:一、java.lang.OutOfMemoryError: PermGen space異常,此爲方法區內存溢出,方法區用來存放class代碼,通常解決辦法就是調大jvm permSize參數值;二、java.lang.OutOfMemoryError: heap space異常,比較常見的堆內存溢出。當然也可以調大jvm參數來解決,但若是不恰當代碼引起的,首先檢查下自己寫的代碼,看哪裏創建了大量對象。若檢查不出來,則使用jmap或jvisualvm導出內存快照。

分析下圖heap dump,這裏又分兩種情況,若左側佔內存大的類名爲com.**.User這種自己定義的業務對象,那在代碼中搜索下此類名就能定位到哪裏創建了大量此對象。若爲String、Integer這種基本類型的對象,則可以使用Eclipse Memory Analyer此類工具進一步分析,可以查看內存大對象的線程堆棧,即可查看代碼調用方法。

 

二:CPU問題

問題現象:前臺顯示卡頓,響應時間長,linux top查看cpu使用率非常高

定位步驟:

1、使用top查看進程pid,java系統通常進程名就叫java

2、使用top -H -p pid查看進程中各線程的CPU使用情況,找出最佔CPU的線程pid,注意這裏其實就是tid

3、通過步驟2我們知道是哪個線程佔CPU了,使用jstack pid打印線程堆棧,查看該線程的代碼調用方法

4、將步驟2線程tid轉換爲16進制,因爲jstack打印出來的threaddump中tid爲16進制,然後在threaddump中搜索,即可找到線程堆棧,這裏30725轉換爲16進制就是7805

這裏有個情況要特別說明,如果步驟4查看的佔用CPU的線程爲java gc線程,通常是由於內存快滿才導致jvm頻繁gc,進而導致CPU高。固此種情況得按上面提到的內存問題去定位解決。Java架構交流學習圈:874811168 面向1-3年經驗 Java開發人員 幫助突破瓶頸 提升思維能力

 

三:線程問題

問題現象1:請求響應時間長,性能測試TPS/QPS上不去,查看CPU佔用又不高

問題現象2:請求響應直接超時,後臺線程相互死鎖

定位:線程問題通常打印一次threaddump是看不出問題的,要多打印幾次對比才能看出問題。建議使用jvisualvm線程頁籤實時查看線程狀態。查看指定業務線程狀態,若長時間處於wait或block狀態,則可確認該問題是由於線程阻塞引起的。查看線程堆棧可查看是調用哪個方法時阻塞的。死鎖問題也是類似定位,線程堆棧裏會提示在等待哪個線程釋放lock,而有兩個線程互相等待即會死鎖。

 

備忘:

jvisualvm連接遠程jvm,遠程jvm添加啓動參數:

-Djava.rmi.server.hostname=10.6.188.43 -Dcom.sun.management.jmxremote.port=18888 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.managementote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章