Java內存溢出分析方法(Eclipse Memory Analyzer 使用簡單入門)


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

 

工具

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

不會用的可以參考一下這個帖子使用 Eclipse Memory Analyzer 進行堆轉儲文件分析

一些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: 設置虛擬機棧內存容量

獲得轉儲文件的一些方法:

     
  1. 使用JVM啟動時的參數設置,如需要在內存溢出時才獲取Dump可以使用-XX:+HeapDumpOnOutOfMemoryError 或者是希望在某個特定時間獲取可以使用 -XX:+HeapDumpOnCtrlBreak
  2.  
  3. 使用一些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方式的報告發送給其他人,方便讀取
分析方法
分析三步曲:
     
  1. 對問題發生時刻的系統內存狀態獲取一個整體印象。
  2.  
  3. 找到最有可能導致內存泄露的元凶,通常也就是消耗內存最多的對象
  4.  
  5. 進一步去查看這個內存消耗大戶的具體情況,看看是否有什么異常的行為。
具體的分析:
查看報告一:內存消耗的整體狀況

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

查看報告二:分析問題的所在

分析對象為什么沒有被回收從而導致一直占用內存。采用根搜索算法來分析對象的事情情況。 點擊報告一種懷疑對象的Detail,可以看到相應的具體分析報告。

Shortest Paths To the Accumulation Point 分析GC根元素到內存消耗聚集點的最短路徑。 Accumulated Objects 查看具體的內存對象信息。

幾種經常出現的內存溢出方式

Java堆溢出

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

java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid1293.hprof ... Heap dump file created [27559990 bytes in 0.233 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap 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:1891Exception in thread "main"  java.lang.StackOverflowError at 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: PermGen space Dumping heap to java_pid1582.hprof ... Heap dump file created [625411 bytes in 0.018 secs] Exception in thread "Reference Handler" Error occurred during initialization of VM java.lang.OutOfMemoryError: PermGen space <<no stack trace available>> Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "Reference Handler"

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

方法區溢出

方法區用於存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。當大量的類產生時填滿方法區,會造成方法去溢出。

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

本機直接內存溢出

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM