利用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是一个不错的工具,里面有不少的小工具给我分析,能够花点时间看看。

相关文章
相关标签/搜索