JVM內存溢出分析java.lang.OutOfMemoryError: Java heap space

JVM內存溢出查詢java.lang.OutOfMemoryError: Java heap space查出具體緣由分爲幾個預備步驟java

一、在運行java程序是必須設置jvm

  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump_OOME.hprof    當內存溢出時 會輸出在/tmp/dump_OOME.hprof目錄下api

#jvm options
#JAVA_OPTS="-Xms8192m -Xmx8192m -Xmn4096m -Djava.awt.headless=true -XX:MaxPermSize=512m -server -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=85 -XX:+DisableExplicitGC -Xnoclassgc -Xverify:none"
JAVA_OPTS="-Xms4096m -Xmx4096m -Djava.awt.headless=true -XX:MaxPermSize=512m -server -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=85 -XX:+DisableExplicitGC -Xnoclassgc -Xverify:none"
JAVA_OPTS="$JAVA_OPTS -javaagent:/usr/local/src/sflowagent.jar -Dsflow.hostname=platform -Dsflow.dsindex=10000"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGC -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -Xloggc:/tmp/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M"
JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump_OOME.hprof"

 

二、能夠在eclipse安裝分析dump_OOME.hprof 的插件MemoryAnalyzerTool

    MemoryAnalyzerTool(也叫MAT)是一款JAVA虛擬機內存映像分析工具,less

    能夠在JAVA程序運行的時候有程序拋出的異常加上已經設置好的參數(-XX:+HeapDumpOnOutOfMemory)調試出內存泄漏或者異常的位置以及緣由跟蹤eclipse

    MemeoryAnalyzer能夠對Dump出來的堆轉儲快照進行分析,重點是確認內存中的對象是不是有必要的,也就是要先確認究竟是出現了內存泄漏(Memory Leak)仍是內存溢出(Memory OverFlow)jvm

 

  

    運行Eclipse,而後單擊菜單欄上「Help=》Install New Software...」工具

    進入軟件源導入界面,你能夠選擇使用URL直接導入,URL導入的地址爲:測試

http://download.eclipse.org/mat/1.7/update-site/

      可是因爲鏡像鏈接不穩定性,我使用的是下載壓縮包zip而後安裝,壓縮包下載地址爲:http://ftp.jaist.ac.jp/pub/eclipse/mat/1.7/MemoryAnalyzer-1.7.0.201706130745.zipspa

    下載完成以後將其導入,"Add》Archive》選擇你下載好的zip文件》OK":插件

  肯定以後勾選"Memory Analyzer for Eclipse IDE"下面的兩項便可,這個是用於Eclipse內部使用的插件,下面一個「Stand-alone Memory Analyzer「是獨立的分析工具,通常不用勾選。調試

  以後單擊「Next"等待一段時間Eclipse計算的需求和依賴文件下載完畢後,一路"next",並接受協議「Finish」便可完成安裝,重啓Eclispe後就可使用MAT了。

 

三、使用Memory Analyzer 分析內存溢出

  

1.設置JVM參數

  JVM的參數能夠用於調試JVM在各類限制條件下的常見BUG,一下簡單介紹幾個參數:

-XX:+HeapDumpOnOutOfMemoryError    //虛擬機在堆異常時生成對存儲快照,後綴通常是.hprof
-Xms    //Java堆的最小值,例如-Xms20m,將Java堆的最小值設置爲20MB
-Xmx    //Java堆的最大值,例如-Xms40m,將Java堆的最大值設置爲40MB

  瞭解了參數以後,能夠對參數進行必定的設置,以便咱們簡單的對MAT工具進行使用測試,設置參數以下:

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D://dump_OOME.hprof -Xms20m -Xmx20m

  之因此將最小和最大的堆設置爲同樣是爲了能避免堆的自動擴展,以及20MB的空間是爲了讓程序能儘快的佔滿使得內存溢出。

  設置JVM的啓動參數可在「Run》Run Configuration》Arguments》Vm arguments」中填寫

2.編寫內存溢出(Memory Leak)代碼

  思路:經過新建集合列表List,而後以while(true)死循環的方式使得List集合不斷添加新的對象,使得其不斷地佔滿堆空間

  代碼:

複製代碼
package com.study;

import java.util.ArrayList;
import java.util.List;

public class TestStudy {

    static class OOMClass { }
    
    public static void main(String[] args) {
        List<OOMClass> list = new ArrayList<OOMClass>();
        while(true) {
            list.add(new OOMClass());
        }
    }

}
複製代碼

  執行代碼,發現輸出以下:

  注意到「java_pid24792.hprof」文件,這個文件是JVM生成的對存儲快照,以後能夠經過MAT工具打開,進行分析追蹤,這個文件將自動保存到你的Eclipse workspace下的工做目錄中,以個人爲例:

 

 

3.打開MAT的Perspective

  因爲MAT工具須要另外打開一個工做視圖(就像Eclipse EE和Java的切換視圖同樣),所以須要在先配置打開"Window》Perspective》Open Perspective》Other...":

  選擇Memory Analysis並肯定:

  完後以後將進入MAT的工做空間視圖,你能夠在Eclipse右上角進行切換回Java或者EE,因爲接下來要使用MAT分析,所以就暫時不切回以前的Java了

4.打開須要分析的堆轉儲快照.hprof文件

  因爲MAT是依賴於生成的堆轉儲快照,而不是在運行的時候自動捕獲,所以,再確認進入MAT的工做空間後,點擊"File》Open Heap Dump》選擇剛生成的「java_pid24792.hprof」文件,一直默認就能夠查看內存問題的分析圖表以及GC根

  你能夠進行一些分析操做,能夠看到Action下的幾個選項:

  a.Histogram:列出每一個類的實例列表;

  b.Dominator:列出最大的對象和他們存在的東西;

  c.Top Comsumer:打印按類和包分組的最昂貴的對象;

  d.Duplicate Classes:檢測由多個類加載器加載的類。

5.使用MAT找出問題存在的對象

  因爲是一個簡單的問題,所以咱們直接選擇Dominator,能夠直接以百分比的形式打印出對象所佔的百分比,通常的內存溢出大部分狀況都是有某一個對象過多存在而未被GC回收致使,因此能夠點開最大百分比的類一級級找,不難找到問題所在:

  能夠看到列出額其中的25條,還有810300條目未列出,這81萬個對象佔據了97.36%的堆空間,所以不難發現是OOMClass類的對象生成過多爲未被回收致使內存溢出。

6.進一步追蹤問題源並進行定位

  在"default_report org.eclipse.mat.api:suspects"的標籤分頁中

  在"Program Suspect 1》Details"點擊後找到"Thread Stack"中追蹤出錯點

  看到出錯點在第13行,找到對應的Java代碼TestStudy的13行:

複製代碼
 1 package com.study;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 public class TestStudy {
 7 
 8     static class OOMClass { }
 9     
10     public static void main(String[] args) {
11         List<OOMClass> list = new ArrayList<OOMClass>();
12         while(true) {
13             list.add(new OOMClass());
14         }
15     }
16 
17 }
複製代碼

  找到了追蹤的出錯位置,以上就是使用Memory Analyzer工具完成的堆棧分析。

相關文章
相關標籤/搜索