天天看點

jvm排查線上gc問題步驟

1. 清楚從程式角度,有哪些原因導緻FGC? 

  • 大對象:系統一次性加載了過多資料到記憶體中(比如SQL查詢未做分頁),導緻大對象進入了老年代。
  • 記憶體洩漏:頻繁建立了大量對象,但是無法被回收(比如IO對象使用完後未調用close方法釋放資源),先引發FGC,最後導緻OOM.
  • 程式頻繁生成一些長生命周期的對象,當這些對象的存活年齡超過分代年齡時便會進入老年代,最後引發FGC. (即本文中的案例)
  • 程式BUG導緻動态生成了很多新類,使得 Metaspace 不斷被占用,先引發FGC,最後導緻OOM.
  • 代碼中顯式調用了gc方法,包括自己的代碼甚至架構中的代碼。
  • JVM參數設定問題:包括總記憶體大小、新生代和老年代的大小、Eden區和S區的大小、元空間大小、垃圾回收算法等等。

2. 清楚排查問題時能使用哪些工具

  • 公司的監控系統:大部分公司都會有,可全方位監控JVM的各項名額。
  • JDK的自帶工具,包括jmap、jstat等常用指令:

    # 檢視堆記憶體各區域的使用率以及GC情況

    jstat -gcutil -h20 pid 1000

    # 檢視堆記憶體中的存活對象,并按空間排序

    jmap -histo pid | head -n20

    # dump堆記憶體檔案

    jmap -dump:format=b,file=heap pid (會停掉程式,謹慎使用)

  • 可視化的堆記憶體分析工具:JVisualVM、MAT、Jprofile(收費)等

3. 排查指南

  • 檢視監控,以了解出現問題的時間點以及目前FGC的頻率(可對比正常情況看頻率是否正常)
  • 了解該時間點之前有沒有程式上線、基礎元件更新等情況。
  • 了解JVM的參數設定,包括:堆空間各個區域的大小設定,新生代和老年代分别采用了哪些垃圾收集器,然後分析JVM參數設定是否合理。
  • 再對步驟1中列出的可能原因做排除法,其中元空間被打滿、記憶體洩漏、代碼顯式調用gc方法比較容易排查。
  • 針對大對象或者長生命周期對象導緻的FGC,可通過 jmap -histo 指令并結合dump堆記憶體檔案作進一步分析,需要先定位到可疑對象。
  • 通過可疑對象定位到具體代碼再次分析,這時候要結合GC原理和JVM參數設定,弄清楚可疑對象是否滿足了進入到老年代的條件才能下結論