天天看點

java eclipse 記憶體溢出_Java記憶體溢出分析方法(Eclipse Memory Analyzer 使用簡單入門)

轉載至:http://outofmemory.cn/java/jvm/OutOfMemoryError-analysis

工具

安裝Memory Analyse Tools(MAT) 工具, 可以直接在eclipse中安裝其相應的插件,安裝方法可以參考另一篇eclipse插件彙總

一些Java記憶體參數設定

-vmargs:  說明後面是VM的參數,是以後面的其實都是JVM的參數了

-Xms20m:  Java初始配置設定的堆記憶體,此處設定為20M -Xmx20m:  Java最大允許配置設定的堆記憶體,此處設定為20M,同時這樣設定表示堆記憶體不許擴充

-XX:PermSize=64M: JVM初始配置設定的非堆記憶體 -XX:MaxPermSize=128M: JVM最大允許配置設定的非堆記憶體,按需配置設定

-XX:+HeapDumpOnOutOfMemoryError: 讓虛拟機在出現記憶體溢出異常時dump出目前記憶體堆轉儲快照以便事後進行分析。 帶上這種參數之後運作Jvm,如果出現相應的記憶體溢出異常,會在目錄下形成一個異常時候的記憶體dump檔案(如java_pid7126.hprof檔案),将這個檔案使用Memory Analyse Tool工具打開就可以看到目前dump記憶體空間的分析内容。

-XX:+HeapDumpOnCtrlBreak:

-Xss: 設定虛拟機棧記憶體容量

獲得轉儲檔案的一些方法:

使用JVM啟動時的參數設定,如需要在記憶體溢出時才擷取Dump可以使用-XX:+HeapDumpOnOutOfMemoryError 或者是希望在某個特定時間擷取可以使用 -XX:+HeapDumpOnCtrlBreak。

使用一些Java工具擷取 ,如 JMap,JConsole 都可以幫助我們得到一個堆轉儲檔案。

MAT工具的一些使用心得:

檔案目錄

使用MAT工具打開擷取的java_pid7126.hprof檔案後,會自動的形成如下的檔案目錄:

java_pid7126.a2s.index

java_pid7126.domIn.index

java_pid7126.domOut.index

java_pid7126.hprof              //轉儲堆檔案java_pid7126.idx.index

java_pid7126.inbound.index

java_pid7126.index

java_pid7126.o2c.index

java_pid7126.o2hprof.index

java_pid7126.o2ret.index

java_pid7126.outbound.index

java_pid7126.threads

java_pid7126_Leak_Suspects.zip //打包的報告,解壓後會形成一個有HTML方式的報告發送給其他人,友善讀取

分析方法

分析三步曲:

對問題發生時刻的系統記憶體狀态擷取一個整體印象。

找到最有可能導緻記憶體洩露的元兇,通常也就是消耗記憶體最多的對象

進一步去檢視這個記憶體消耗大戶的具體情況,看看是否有什麼異常的行為。

具體的分析:

檢視報告一:記憶體消耗的整體狀況

在OverView上的Report中可以選擇 Leak Suspects ,來檢視整體對象消耗。下方有一個警告可以看到目前系統自動幫忙分析的懷疑對象。在這個懷疑對象中便可以發現大多數的問題。

檢視報告二:分析問題的所在

分析對象為什麼沒有被回收進而導緻一直占用記憶體。采用根搜尋算法來分析對象的事情情況。 點選報告一種懷疑對象的Detail,可以看到相應的具體分析報告。

Shortest Paths To the Accumulation Point 分析GC根元素到記憶體消耗聚集點的最短路徑。 Accumulated Objects 檢視具體的記憶體對象資訊。

幾種經常出現的記憶體溢出方式

Java堆溢出

異常資訊: “java.lang.OutOfMemoryError”。會跟着進一步提示Java heap space.

java.lang.OutOfMemoryError:Javaheap space

Dumpingheap to java_pid1293.hprof ...Heapdumpfile created [27559990bytes in0.233secs]Exceptioninthread "main"java.lang.OutOfMemoryError:Javaheap space

at java.util.Arrays.copyOf(Arrays.java:2245)at java.util.Arrays.copyOf(Arrays.java:2219)at java.util.ArrayList.grow(ArrayList.java:242)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)at java.util.ArrayList.add(ArrayList.java:440)at com.valentine.jvm.analyzer.exception.HeapOOM.main(HeapOOM.java:16)

Java堆溢出記憶體問題分析步驟總結: 1. dump出來堆轉儲快照 2. 使用MAT工具對dump出來的堆轉儲快照進行分析,重點是确認記憶體中得對象是否必要的,這樣可以厘清楚到底是出現了記憶體洩露(Memory Leak)還是記憶體溢出(Memory Overflow) 3. 如果是記憶體洩露,進一步通過MAT工具分析洩露對象到GC Roots的引用鍊。找到洩露對象是通過怎樣的路徑與GC Roots相關聯并導緻垃圾收集器無法自動回收的。 4. 如果不存在洩露,那麼就是記憶體中得對象卻是都還必須活着,就應當檢查虛拟機的堆參數(-Xmx與-Xms),與機器實體記憶體對比看是否可以調大,從代碼上檢查是否存在某些對象生命周期過長、持有狀态時間過長的情況,嘗試減少程式運作期間的記憶體。

虛拟機和本地方法棧溢出

在HotSpot虛拟機中并不區分虛拟機棧和本地方法棧。到對于HostSpot來說-Xoss參數(設定本地方法棧大小)是存在的,但實際是無效的,棧容量隻由-Xss參數決定。

異常情況: * 如果線程請求的棧深度大于虛拟機所允許的最大深度,将抛出StackOverflowError異常 * 如果虛拟機在擴充棧時無法申請到足夠的記憶體空間時,将抛出OutOfMemoryError異常

異常資訊:

stack length:1891Exceptioninthread "main"java.lang.StackOverflowErrorat com.valentine.jvm.analyzer.exception.JavaVmStackSOF.stackLeak(JavaVmStackSOF.java:8)at com.valentine.jvm.analyzer.exception.JavaVmStackSOF.stackLeak(JavaVmStackSOF.java:9)at com.valentine.jvm.analyzer.exception.JavaVmStackSOF.stackLeak(JavaVmStackSOF.java:9)……at com.valentine.jvm.analyzer.exception.JavaVmStackSOF.stackLeak(JavaVmStackSOF.java:9)

在單線程下,無論是由于棧幀太小還是虛拟機棧容量太小,當記憶體無法配置設定的時候,虛拟機抛出的都是StackOverflowError異常。 在多線程下,通過不斷的建立線程的方式可以産生記憶體溢出OutOfMemoryError異常。

在多線程情況下,給每個線程配置設定的記憶體越大,越容易産生記憶體溢出異常。由于作業系統配置設定給每個程序的記憶體是有限的,32位的Windows限制為2GB。虛拟機提供了參數來控制Java堆和方法區的這兩部分記憶體的最大值。剩餘的2GB減去Xmx,再減去MaxPermSize,忽略掉很小的程式計數器記憶體。如果虛拟機程序本身耗費的記憶體不計算,剩下的記憶體就是有虛拟機棧和本地方法棧瓜分了。此時如果每個線程配置設定到的虛拟機棧容量越大,可以建立的線程數量自然就越少,建立線程時就越容易把剩下的記憶體耗盡。 如果建立過多線程導緻的記憶體溢出,在不能減少線程數或者更換64位虛拟機的情況下,就隻能通過減少最大堆或者減少棧容量來擷取更多的線程。

出現StackOverflowError的時候有錯誤堆棧可以讀,即時加入+HeapDumpOnOutOfMemoryError也不會dump異常堆記憶體。

運作時常量池溢出

如果要項運作時常量池中添加内容,最簡單的方法就是使用String.intern()這個Native方法。

異常資訊:

java.lang.OutOfMemoryError:PermGenspace

Dumpingheap to java_pid1582.hprof ...Heapdumpfile created [625411bytes in0.018secs]Exceptioninthread "Reference Handler"Erroroccurred during initialization of VM

java.lang.OutOfMemoryError:PermGenspace

<>Exception:java.lang.OutOfMemoryErrorthrown fromthe UncaughtExceptionHandlerinthread "Reference Handler"

從異常中可以看出OutOfMemoryError後報的是PermGen space,說明是方法區溢出。

方法區溢出

方法區用于存放Class的相關資訊,如類名、通路修飾符、常量池、字段描述、方法描述等。當大量的類産生時填滿方法區,會造成方法去溢出。

方法區溢出也是一種常見記憶體溢出異常,一個類如果要被垃圾收集器回收,判斷條件非常苛刻。

本機直接記憶體溢出

DirectMemory容量可通過-XX:MaxDirectMemorySize指定,如果不指定,則預設與Java堆的最大值(-Xmx)一樣。