天天看點

Java程式記憶體分析:使用mat工具分析記憶體占用

造成outofmemoryerror原因一般有2種:

1、記憶體洩露,對象已經死了,無法通過垃圾收集器進行自動回收,通過找出洩露的代碼位置和原因,才好确定解決方案;

2、記憶體溢出,記憶體中的對象都還必須存活着,這說明java堆配置設定空間不足,檢查堆設定大小(-xmx與-xms),檢查代碼是否存在對象生命周期太長、持有狀态時間過長的情況。

Java程式記憶體分析:使用mat工具分析記憶體占用

這樣在e盤的jmap檔案夾裡會有一個map.bin的堆資訊檔案 

Java程式記憶體分析:使用mat工具分析記憶體占用

    mat可以為我們生成多個報告:

Java程式記憶體分析:使用mat工具分析記憶體占用
Java程式記憶體分析:使用mat工具分析記憶體占用

    下面來看看生成的這些資料對我們有什麼幫助

Java程式記憶體分析:使用mat工具分析記憶體占用

    從上圖可以看到它的大部分功能,在餅圖上,你會發現轉儲的大小和數量的類,對象和類加載器。

正确的下面,餅圖給出了一個印象最大的對象轉儲。移動你的滑鼠一片看到對象中的對象的細節檢查在左邊。下面的action标簽中:

histogram可以列出記憶體中的對象,對象的個數以及大小。

dominator tree可以列出那個線程,以及線程下面的那些對象占用的空間。

top consumers通過圖形列出最大的object。

leak suspects通過ma自動分析洩漏的原因。

Java程式記憶體分析:使用mat工具分析記憶體占用

class name : 類名稱,java類名

objects : 類的對象的數量,這個對象被建立了多少個

shallow heap :一個對象記憶體的消耗大小,不包含對其他對象的引用

retained heap :是shallow heap的總和,也就是該對象被gc之後所能回收到記憶體的總和

一般來說,shallow heap堆中的對象是它的大小和保留記憶體大小相同的對象是堆記憶體的數量時,将釋放對象被垃圾收集。

保留設定一組主要的對象,例如一個特定類的所有對象,或所有對象的一個特定的類裝入器裝入的類或者隻是一群任意對象,是釋放的組對象如果所有對象的主要設定變得難以接近的。保留設定包括這些對象以及所有其他對象隻能通過這些對象。保留大小是總堆大小中包含的所有對象的保留。摘自eclipse

Java程式記憶體分析:使用mat工具分析記憶體占用

這兒借助工具提供的regex正則搜尋一下我們自己的類,排序後看看哪些相對是占用比較大的。

Java程式記憶體分析:使用mat工具分析記憶體占用

左邊可以看到類的詳細使用,比如所屬包,父類是誰,所屬的類加載器,記憶體位址,占用大小和回收情況等

Java程式記憶體分析:使用mat工具分析記憶體占用

這兒有個工具可以根據自己的需求分組查找,預設根據class分組,類似我們sql裡的group by了~~

Java程式記憶體分析:使用mat工具分析記憶體占用
Java程式記憶體分析:使用mat工具分析記憶體占用

這個是overview中的 heap dump overview視圖,從工具欄中點開,這是一個全局的記憶體占用資訊

used heap dump

79.7 mb

number of objects

1,535,626

number of classes

8,459

number of class loaders

74

number of gc roots

2,722

format

hprof

jvm version

time

格林尼治标準時間+0800上午9時20分37秒

date

2014-7-2

identifier size

32-bit

file path

e:\jmap\map.bin

file length

108,102,005

total: 12 entries

然後可以點開systemproperties和thread overview進行檢視,我這裡就不貼了内容比較多。

Java程式記憶體分析:使用mat工具分析記憶體占用

我們可以看到ibatis占了較多記憶體

Java程式記憶體分析:使用mat工具分析記憶體占用

這張圖展示的是占用記憶體比較多的對象的分布,下面是具體的一些類和占用。

Java程式記憶體分析:使用mat工具分析記憶體占用

按等級分布的類使用情況,其實也就是按使用次數檢視,java.lang.class被排在第一

Java程式記憶體分析:使用mat工具分析記憶體占用

還有一張圖是我們比較關心的,那就是按包名看占用,根據包我們知道哪些公共用的到jar或自己的包占用

Java程式記憶體分析:使用mat工具分析記憶體占用

這樣就可以看到包和包中哪些類的占用比較高。

Java程式記憶體分析:使用mat工具分析記憶體占用

從這份報告,看到該圖深色區域被懷疑有記憶體洩漏,可以發現整個heap隻有79.7m記憶體,深色區域就占了62%。是以,mat通過簡單的報告就說明了項目是有可疑代碼的,具體點開詳情來找到類,

Java程式記憶體分析:使用mat工具分析記憶體占用
Java程式記憶體分析:使用mat工具分析記憶體占用
Java程式記憶體分析:使用mat工具分析記憶體占用

點選滑鼠,在list objects-> with outgoing references下可以檢視該類都引用了什麼對象,由此檢視是否因為其他對象導緻的記憶體問題。

下面繼續檢視pool的gc root

如下圖所示的上下文菜單中選擇 path to gc roots -> exclude weak references, 過濾掉弱引用,因為在這裡弱引用不是引起問題的關鍵。

進入檢視即可,我這兒的代碼沒有問題,就不用貼了。

Java程式記憶體分析:使用mat工具分析記憶體占用

the classloader/component "org.apache.catalina.loader.webappclassloader @ 0xa34cde8" occupies 19,052,864 (22.80%) bytes. the memory is accumulated in one instance of "java.util.hashmap$entry[]" loaded by "<system class loader>".

keywords

java.util.hashmap$entry[]

org.apache.catalina.loader.webappclassloader @ 0xa34cde8

這段話是在工具中提示的,他告訴我們webappclassloader占了19,052,864 位元組的容量,這是tomcat的類加載器,jdk自帶的系統類加載器中占用比較多的是hashmap。這個其實比較正常,大家經常用map作為存儲容器。

除了在上一頁看到的描述外,還有shortest paths to the accumulation point和accumulated objects部分,這裡說明了從gc root到聚集點的最短路徑,以及完整的reference chain。觀察accumulated objects部分,java.util.hashmap的retained heap(size)最大,是以明顯類執行個體都聚集在hashmap中了。

Java程式記憶體分析:使用mat工具分析記憶體占用

來看看accumulated objects by class區域,這裡能找到被聚集的對象執行個體的類名。java.util.hashmap類上頭條了,被執行個體化了5573次,從這兒看出這個程式不存在什麼問題,因為這個數字是比較正常的,但是當出問題的時候我們都會看到比較大的自定義類會在前面,而且占用是相當高。

當然,mat這個工具還有很多的用法,這裡把我了解的分享給大家,不管如何,最終我們需要得出系統的記憶體占用,然後對其進行代碼或架構,伺服器的優化措施!