利用MemoryAnalyzer進行OutOfMemoryError的診斷分析

     這篇帖子只介紹利用MemoryAnalyzer進行簡單的JVM的堆的分析,至於JVM的內部結構是怎麼樣的,這裏不進行分析。好吧,廢話很少說;首先 若是咱們要分析JVM某個時刻的Heap的對象分配狀況,咱們就必需要dump這個時刻的JVM的heap(堆);有如下幾個辦法進行dump某個時刻 JVM的heap內容:java

         一、 使用$JAVA_HOME/bin/jmap -dump來觸發, 
                eg:jmap-dump:format=b,file=/home/longhao/heamdump.out <pid>
         二、 使用$JAVA_HOME/bin/jcosole中的MBean,到 MBean>com.sun.management>HotSpotDiagnostic>操做>dumpHeap中,點擊 dumpHeap按鈕。生成的dump文件在   java應用的根目錄下面。
         三、在應用啓動時配置相關的參數 -XX:+HeapDumpOnOutOfMemoryError,當應用拋出OutOfMemoryError時生成dump文件。
         四、使用hprof。啓動虛擬機加入-Xrunhprof:head=site,會生成java.hprof.txt文件。該配置會致使jvm運行很是的慢,不適合生產環境。app

利用MemoryAnalyzer進行Heap分析
        去eclipse官網上去下載MemoryAnalyzer,能夠下載非插件版的,這樣MemoryAnalyzer運行起來比較快,若是是 eclipse插件版進行可能會致使eclipse卡死。本人下載的版本是MemoryAnalyzer-1.2.0.20120530- win32.win32.x86_64。eclipse

 1、Java代碼樣例jvm

[java] view plain copy工具

 

  1. package org.ph.javaee.javaheap;  
  2.   
  3.   
  4. import java.util.Map;  
  5.   
  6. import java.util.HashMap;  
  7.   
  8.   
  9. /** 
  10.  
  11.  * JVMOutOfMemoryErrorSimulator 
  12.  
  13.  *  
  14.  
  15.  * @author PH 
  16.  
  17.  *  
  18.  
  19.  */  
  20.   
  21. public class JVMOutOfMemoryErrorSimulator {  
  22.   
  23.        private final static int NB_ITERATIONS = 500000;  
  24.   
  25.        // ~1 KB data footprint  
  26.   
  27.        private final static String LEAKING_DATA_PREFIX = "datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata";  
  28.   
  29.        // Map used to stored our leaking String instances  
  30.   
  31.        private static Map<String, String> leakingMap;  
  32.   
  33.        static {  
  34.   
  35.               leakingMap = new HashMap<String, String>();  
  36.   
  37.        }  
  38.   
  39.   
  40.        public static void main(String[] args) {  
  41.   
  42.               System.out.println("JVM OutOfMemoryError Simulator 1.0");  
  43.   
  44.               System.out.println("Author: Pierre-Hugues Charbonneau");  
  45.   
  46.               System.out.println("http://javaeesupportpatterns.blogspot.com/");  
  47.   
  48.               try {  
  49.                      for (int i = 0; i < NB_ITERATIONS; i++) {  
  50.                            String data = LEAKING_DATA_PREFIX + i;  
  51.                       
  52.                            // Add data to our leaking Map data structure...  
  53.   
  54.                            leakingMap.put(data, data);  
  55.                      }  
  56.   
  57.               } catch (Throwable any) {  
  58.   
  59.                      if (any instanceof java.lang.OutOfMemoryError) {  
  60.   
  61.                             System.out.println("OutOfMemoryError triggered! "  
  62.   
  63.                                          + any.getMessage() + " [" + any + "]");  
  64.                      } else {  
  65.   
  66.                            System.out.println("Unexpected Exception! " + any.getMessage()  
  67.   
  68.                                          + " [" + any + "]");  
  69.                      }  
  70.               }  
  71.               System.out.println("simulator done!");  
  72.   
  73.        }  
  74. }  



 
 2、設置JVM啓動參數
         在此咱們把JVM堆的最大內存設置爲512m,而且讓程序運行過程當中出現內存溢出的時候會dump當時的JVM對內存的內容,因此須要加上 XX:+HeapDumpOnOutOfMemoryError參數;所以按照如下步驟在eclipse中加入啓動參數spa


 3、運行程序
        運行程序,而後觀察控制檯的輸出,輸出結果以下:.net

        從以上的輸出結果來看,此程序已經拋出了OutOfMemoryError了,而且生成了一個heap文件,文件名爲java_pid3880.hprof,下一步咱們就能夠拿這個文件在MemoryAnalyzer分析了。插件


 4、導入heap文件分析orm

        導入後按照如下步驟執行進行內存泄露的可疑分析;對象

 

 鼠標點擊紅色的部分會出現菜單,選中菜單的第一行的List objects > With Incoming references,就會出現如下界面

        此圖展示了HashMap$Entry被引用的路徑,HashMap$Entry被一個java.util.HashMap的table實例變量引用, 而這個HashMap又被JVMOutOfMemberyErrorSimulator類變量leakingMap引用,因此經過這些路徑就很容易找到是 哪段代碼致使的內存溢出。
        經過以上分析咱們就發現,類JVMOutOfMemberyErrorSimulator的leakingMap變量的內容太大致使了內存溢出,因此這樣就能很快定位到問題。
        其中注意Shallow vs. Retained Heap的區別,這裏不進行解釋,點擊MemoryAnalyzer的Help菜單裏面的HelpContents就能夠查找到
        這裏解釋下Java Local,JVM裏面的類變量,實例變量的名字在JVM裏面都有記錄,而局部變量是沒有記錄的,因此Java Local在這裏就表明局部變量。

       總結:以上的這些分析方法是入門級別的,現實中的OOM分析確定比這更復雜,本人就曾經遇到過不少詭異的OOM。但在通常狀況下,若是出現OOM,那麼我 們確定須要對JVM的heap進行分析,這篇帖子是一個很好的思惟方法;固然你也能夠利用其餘的工具進行heap分析,但思路大概都差不 多;MemoryAnalyzer是一個不錯的工具,裏面有不少的小工具給我分析,能夠花點時間看看。

相關文章
相關標籤/搜索