JVM內存溢出實戰和總結(採用VisualVM工具)

JVM內存溢出實戰和總結

一、通用技巧

  • 某一天任務進程突然不工作了。查看日誌,是昨晚10點就停止作業了。查看進程狀態,還活着。查看jstack,沒有死鎖,還有進程在跑着。

sudo ps -ef | grep java
sudo jstack 進程號

  • 懷疑內存溢出,準備dump內存鏡像,先往上翻一下日誌,grep memory 。找到了關鍵日誌Out of Memory。

導出日誌的命令:

jmap -dump:live,format=b,file=/tmp/業務名稱-201909021657.bin 進程號

  • 去VisualVM官方網下載 visualvm,找一個和自己系統JDK相符的版本下載即可。我在JDK8用visualvm_142版本,win10。
  • 然後將下載到本機的dump文件丟給visualvm.exe圖標。或者File->load 找到dump文件打開即可。
  • 可以看到基本visualvm解析了很多內存信息。
    可以看到類的個數和實例個數

在這裏插入圖片描述
基本沒啥有用的信息

  • 重點是對象池板塊和對象查詢語言版本

在這裏插入圖片描述

這纔是我們診斷溢出的利器。

對象查詢語言終端 OQL Console,類似SQL一樣,可以幫我們更專業的瞭解內存情況。不過我們基本用不到,很多溢出場景都可以利用對象池Objects可以看出貓膩了。

  • 利用對象池找出可能溢出對象。

在這裏插入圖片描述

點擊Count,指示按照實例對象個數做降序。

之後看第一列的類全限定名。

我們知道所有自定類都是由JDK類組成,可以根據類組成結構可以知道對象的個數應該呈現樹形結構。
即基礎類的個數比較多,自定義類個數比較少。

所以我們不難發現,個數排名靠前都是JDK類庫的對象。

換而言之,如果是自定義類混進了前排,那麼我們記下他然後逐個排查。混進前排的類,要麼是業務特殊性造成,要麼是業務代碼寫的不合理,要麼是確實內存溢出了。

本例子我們找到了,兩個對象,而且這兩個對象是組合關係。
在這裏插入圖片描述

不難發現,他們連個數都是一樣,明顯泄漏了,如果不放心可以隔一段時間再dump一下,可以瞭解他的增長速度和存活時間。(這一步我就不做了,因爲十有八九是它們泄漏了)

二、業務分析技巧

這裏需要自己瞭解自己的業務代碼邏輯,以及一個理論:一個對象沒法被回收,那麼它一定有強引用(其他引用不會造成OOM)。

強引用大多都是因爲靜態變量引用造成了,其他局部變量都在方法塊結束就會被回收了

常見的造成泄漏的強引用,要麼是數組或者是隊列,所以在排查溢出代碼時候多加關照。

瞭解這些,找出溢出代碼就不難了。

三、總結:

  • 個數排名靠前都是JDK類庫的對象
  • 如果是自定義類混進了前排,那麼我們記下他然後逐個排查。混進前排的類,要麼是業務特殊性造成,要麼是業務代碼寫的不合理,要麼是確實內存溢出了
  • 一個對象沒法被回收,那麼它一定有強引用(其他引用不會造成OOM)
  • 強引用大多都是因爲靜態變量引用造成了,其他局部變量都在方法塊結束就會被回收了
  • 常見的造成泄漏的強引用,要麼是數組或者是隊列
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章