Java內存問題分析與定位

簡介

 

  •  JNI方法申請的native 內存,通常是在JDK庫裏;本地 C++ 方法直接通過 malloc申請的內存,不受JVM管控。
  • 堆內內存: 指Java堆,GC算法管理的內存區域。
  • 堆外內存: Java堆外的內存都叫堆外。可以細分爲JVM內部,Metaspace, JNI方法申請的native內存三部分。通常說的直接內存 DirectBuffer , 會記錄在Internal區。

JNI申請的native內存不受JVM管控。

GC算法和日誌解讀

  • Java堆進一步劃分,Eden, s0, s1, 老年代。
  • 不同GC算法對存活對象的掃描和清理方式不一樣,對業務代碼的運行影響不一樣,因此,不同的業務場景,選合適的GC算法和GC參數。

一般建議 parallel scavenge (JDK8默認GC),適用大部分場景。

 

 GC日誌組成: GC時間, GC原因, GC位置(年輕代, 老年代, 元空間), 釋放內存大小, 持續時間。

原則上, 優先看Full GC的頻率, 其次查看日誌STW階段(比如G1裏標記了pause, CMS裏mark和remark)階段消耗時間,

最後查看內存收縮情況。

用JMap工具可以轉儲Java堆到快照文件,然後用MAT工具分析,只要是堆內問題,就用MAT工具。

  • 可以詳細查看Java堆內java對象佔比
  • 可多維度分析堆內對象分佈,查找可疑的內存最大佔比的對象。
  • 可分析對象的依賴路徑,查找爲是否原因。

GC異常分析與定位

現象:

  • 業務偶爾出現超時現象
  • cpu負載很高

分析與解決:

  1. 超時或負載高很可能是GC異常表象,此時需要查看GC日誌,結合實際業務,分析GC行爲,找到GC異常根因。
  2. GC頻繁,STW時間長,可能原因有:存活對象多,堆大小或堆各子區域大小劃分不合理。
  3. 存活對象多,則可能存在內存泄漏,可能是代碼邏輯問題,進一步可用MAT工具分析Java對象。

 

 OOM問題分析與定位

1. 根據OOM錯誤提示,由於配置原因導致Java堆或者Metaspace區域oom,

判斷標準之一是程序是否穩定運行,實際內存佔用有升有降。

2. Metaspace本身沒有限制,如果設置了MaxMetaspaceSize,則受限這個配置。

3.如果內存持續增長超出業務實際可能使用的內存量,則可能存在內存泄漏。

 

內存泄漏位置判斷

1. 通過異常日誌提示,

eg, Java.lang.OutOfMemoryError: Java heap space,

Java.lang.OutOfMemoryError: metadata space,

Java.lang.OutOfMemoryError: Direct buffer space,

2. 開啓NMT(啓動參數上加上 -XX: NativeMemoryTracking=detail), 可幫助判斷那塊內存區域內存泄漏。

  • Java堆,即Java Heap
  • Metaspace, 即class區域
  • JVM內部
  • JNI申請的native內存

 

堆內內存泄漏排查

1. 只要是Java堆或Metaspace區域內存泄漏,都可以轉儲Java堆快照文件,用MAT工具分析。

2. 多維度分析堆內對象分佈,查找可疑內存最大佔比的對象。

3.分析對象依賴路徑,查找未釋放原因。

 

堆外內存泄漏排查

1. 首先通過上文手段判斷內存泄漏位置。

2.根據位置對應的功能,進一步查找具體的異常代碼。

3. JNI申請的native內存本身已超出JVM控制範圍,沒辦法用JVM工具排查。

藉助操作系統工具pmap排查,可查看進程內存映射,查找可疑內存。

 

案例分析

例一.

某業務發現cpu值偶爾飆升,排查發現GC停頓較長。

進一步發現大量存活對象有些異常,懷疑內存泄漏。

最後heap dump 後使用MAT分析,發現一全局HashMap持有了大量重複對象,

業務代碼裏移除操作由問題,實際未移除,修復後問題解決。

例二.

某業務線遷移OSGI框架後,JVM無法響應外部請求,排查GC日誌發現是因爲Metaspace空間不足,

頻繁full gc 導致;進一步排查發現OSGI環境下,不停的defineClass, 最後發現某基礎組件會不停創建,

實際上, 全局只需一份,修改後問題解決。

例三.

某業務線集羣,進程RSS超出Xmx很多,開啓NMT後發現確實有不受JVM控制的內存申請,

最後通過監控 malloc 監控每次請求,發現一處本地方法調用,sun.nio.fs.unitNativeDispatcher.opendir, 

進一步分析,代碼中有使用Files.list函數,但沒有釋放動作。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章