• 利用MemoryAnalyzer进行OutOfMemoryError的诊断分析


    这篇帖子只介绍利用MemoryAnalyzer进行简单的JVM的堆的分析,至于JVM的内部结构是怎么样的,这里不进行分析。好吧,废话不多说;首先如果我们要分析JVM某个时刻的Heap的对象分配情况,我们就必须要dump这个时刻的JVM的heap(堆);有以下几个办法进行dump某个时刻JVM的heap内容:

             1、 使用$JAVA_HOME/bin/jmap -dump来触发, 
                    eg:jmap-dump:format=b,file=/home/longhao/heamdump.out <pid>
             2、 使用$JAVA_HOME/bin/jcosole中的MBean,到MBean>com.sun.management>HotSpotDiagnostic>操作>dumpHeap中,点击 dumpHeap按钮。生成的dump文件在   java应用的根目录下面。
             3、在应用启动时配置相关的参数 -XX:+HeapDumpOnOutOfMemoryError,当应用抛出OutOfMemoryError时生成dump文件。
             4、使用hprof。启动虚拟机加入-Xrunhprof:head=site,会生成java.hprof.txt文件。该配置会导致jvm运行非常的慢,不适合生产环境。

    利用MemoryAnalyzer进行Heap分析
            去eclipse官网上去下载MemoryAnalyzer,可以下载非插件版的,这样MemoryAnalyzer运行起来比较快,如果是eclipse插件版进行可能会导致eclipse卡死。本人下载的版本是MemoryAnalyzer-1.2.0.20120530-win32.win32.x86_64。

     一、Java代码样例

    [java] view plaincopy

    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. }  



     
     二、设置JVM启动参数
             在此我们把JVM堆的最大内存设置为512m,并且让程序运行过程中出现内存溢出的时候会dump当时的JVM对内存的内容,所以需要加上XX:+HeapDumpOnOutOfMemoryError参数;因此按照以下步骤在eclipse中加入启动参数


     三、运行程序
            运行程序,然后观察控制台的输出,输出结果如下:

            从以上的输出结果来看,此程序已经抛出了OutOfMemoryError了,并且生成了一个heap文件,文件名为java_pid3880.hprof,下一步我们就可以拿这个文件在MemoryAnalyzer分析了。


     四、导入heap文件分析

            导入后按照以下步骤执行进行内存泄露的可疑分析;

     

     鼠标点击红色的部分会出现菜单,选中菜单的第一行的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是一个不错的工具,里面有很多的小工具给我分析,可以花点时间看看。

  • 相关阅读:
    Oracle的基本语法(增删改查)
    Oracle存储过程的学习
    Oracle创建联合主键
    Oracle查询当前用户的信息
    Oracle给创建函数的权限
    Oracle给存储过程权限及触发器
    Unity3D脚本的生命周期(执行顺序)
    Unity性能优化的N种武器
    序列化、反序列化(Serializable特性)
    Unity 读取资源(图片)
  • 原文地址:https://www.cnblogs.com/xiang--liu/p/9710189.html
Copyright © 2020-2023  润新知