排查Java記憶體洩露實戰(內附各種排查工具介紹)
今天剛剛才加一個故障review會議, 故障非常典型, google下也可以找到相似案例介紹。 在排查問題的過程中,使用了大量的工具, 發現有問題的地方還不只一個,總結一下. (本篇文章不會重點描述案例本身,重點會介紹個人對java記憶體洩露問題的排查思路和各種工具的使用)。
java記憶體洩露典型特徵
現象一: 堆/Perm 區不斷增長, 沒有下降趨勢(回收速度趕不上增長速度), 最後不斷觸發FullGC, 甚至crash(如下兩張圖是同一個應用的GC和Perm資料, GC觸發原因確認是Perm不足). 一般是現象二的晚期表現。
現象二: 每次FullGC後, 堆/Perm 區在慢慢的增長, 最後不斷觸發FullGC, 甚至crash(如下圖: 示意圖)
java記憶體洩露場景---PermGen space
原因: 說明Perm不足. Perm存放class,method相關物件,以及執行時常量物件. 如果一個應用載入了大量的class, 那麼Perm區儲存的資訊一般會比較大.另外大量的intern String物件也會導致Perm區不斷增長。此區域大小由-XX:MaxPermSize引數進行設定. (jdk8相關引數已經改變, 這裡不討論)
案例: Groovy動態編譯class, xstream String.intern
本質原因: ClassLoader.defineClass和java.lang.String.intern在大量不適宜的場景被呼叫.
解決方案:
方案1(直接有效): 使用btrace相關工具輸出呼叫ClassLoader.defineClass棧資訊, 從棧資訊來追溯問題. (程式碼如下圖). 但Btrace 不能trace jvm native方法(官方release btrace 1.3.1中版本宣告可以trace native方法, 但嘗試無效。如果你清楚如何使用,麻煩告知一下,謝謝)。
用JProfiler來trace String.intern方法棧
方案2: dump heap, 看看哪些class有異常現象(數量), String被Perm區引用的物件資訊等.但這種方式不太直觀,可以從String資料看看發現可疑問題,沒有方案1直觀。(如下圖: 如果能在日常除錯推薦JProfiler)
方案3: 增加-XX:+TraceClassLoading和-XX:+TraceClassUnloading, 看看哪些class載入了,哪些class解除安裝了. 如果一些特殊的class一直被載入而沒有被解除安裝說明也是有問題的。(如下圖)
方案4:執行jmap -permgen(jstat -gcutil 可以檢視記憶體增長速度和區域)命令看看Perm區中的內容, 初步確定是否存在問題 (如下圖)
java記憶體洩露場景---Java heap space
原因: 長生命週期的物件引用了短生命週期(應該儘快GC回收掉)的物件,最後造成一個物件已經不能在堆區分配足夠空間. 注: 這種現象不能完全肯定是記憶體洩露, 比如: heap本身的設定的過小.
案例: 我個人沒有遇到過這種案例, 但模擬過這種情形的Demo: 參考我的《深入淺出JProfiler》文章, 也學習過其他同學的案例: 例如:引數過大並且頻繁超時導致記憶體洩露
解決方案:
- 觸發FullGC, dump live heap. 標記堆中物件數量, 重點關注可疑物件
- 觸發FullGC, dump live heap. 標記堆中物件數量, 重點關注可疑物件
- 對比步驟1和步驟2 相同物件的數量和大小, 找出可疑物件一一進行排查確認。
- 如果步驟3依然無法明確有問題的物件, 那就多執行幾次步驟1和步驟2。在此過程中可以調整GC觸發時間, 模擬真實的故障場景 :)
- 看看GC後堆的大小是否增長, 如果沒有不斷增長, 並且持續一段較長時間, 那基本正常。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69942496/viewspace-2843789/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 如何排查Java記憶體洩露(內附各種排查工具介紹)Java記憶體洩露
- Python實現記憶體洩露排查的示例Python記憶體洩露
- nodejs爬蟲記憶體洩露排查NodeJS爬蟲記憶體洩露
- netty 堆外記憶體洩露排查盛宴Netty記憶體洩露
- 記一次"記憶體洩露"排查過程記憶體洩露
- 一次Kafka記憶體洩露排查經過Kafka記憶體洩露
- 記一次尷尬的Java應用記憶體洩露排查Java記憶體洩露
- 記一次Go websocket 專案記憶體洩露排查 + 使用Go pprof定位記憶體洩露GoWeb記憶體洩露
- 工具介紹 - 捕獲Windows CE的記憶體洩露Windows記憶體洩露
- 一次 Java 記憶體洩漏的排查Java記憶體
- 實戰Go記憶體洩露Go記憶體洩露
- redisson記憶體洩漏問題排查Redis記憶體
- java 堆外記憶體排查Java記憶體
- 分散式 | 令人頭疼的堆外記憶體洩露怎麼排查?分散式記憶體洩露
- JVM 常見線上問題 → CPU 100%、記憶體洩露 問題排查JVM記憶體洩露
- 排查Java的記憶體問題Java記憶體
- iOS 記憶體洩漏排查方法及原因分析iOS記憶體
- 介紹Java中的記憶體洩漏Java記憶體
- 一次 Java 記憶體洩漏排查過程,漲姿勢Java記憶體
- 一次排查Java專案記憶體洩漏的過程Java記憶體
- Java記憶體洩露的原因Java記憶體洩露
- JAVA 記憶體洩露的理解Java記憶體洩露
- 學習Java:記憶體洩露Java記憶體洩露
- JAVA堆外記憶體排查小結Java記憶體
- 記錄一次記憶體洩漏排查過程記憶體
- 記憶體洩漏與排查流程——安卓效能優化記憶體安卓優化
- 記憶體洩露記憶體洩露
- 線上記憶體洩露定位--memleak工具記憶體洩露
- leaks工具查詢記憶體洩露記憶體洩露
- Java 8 記憶體管理原理解析及記憶體故障排查實踐Java記憶體
- 記一次堆外記憶體洩漏排查過程記憶體
- 內部Handler類引起記憶體洩露記憶體洩露
- 異常連線導致的記憶體洩漏排查記憶體
- 一次glide記憶體洩漏排查分析IDE記憶體
- js記憶體洩露JS記憶體洩露
- JavaScript記憶體洩露JavaScript記憶體洩露
- 記憶體洩露嗎記憶體洩露
- 記一次使用windbg排查記憶體洩漏的過程記憶體