利用Memory Analyzer来对OOM进行分析

一、什么是OOM?

    OOM就是outOfMemory,内存溢出!可能是每一个java人员都能遇到的问题!原因是堆中有太多的存活对象(GC-ROOT可达),占满了堆空间。

二、怎么解决?

  • 利用MemoryAnalyzer进行Heap分析:去eclipse官网上去下载MemoryAnalyzer,可以下载非插件版的,这样MemoryAnalyzer运行起来比较快,如果是eclipse插件版进行可能会导致eclipse卡死。直接从官网下载程序包 http://www.eclipse.org/mat/downloads.php,解压可直接使用。
  • 拿到内存溢出时的heapdump.hprof文件,可在程序启动时增加启动参数: -XX:+HeapDumpOnOutOfMemoryError XX:HeapDumpPath=/test/test/test.hprof。

实例分析

import java.util.Map;  
import java.util.HashMap;  
  
public class HeapDumpMain{  
  
       private final static int NB_ITERATIONS = 500000;  
  
       private final static String LEAKING_DATA_PREFIX = "datadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadatadata";  
  
       private static Map<String, String> leakingMap;  
  
       static {  
  
              leakingMap = new HashMap<String, String>();  
  
       }  
  
  
       public static void main(String[] args) {  
  
              System.out.println("JVM OutOfMemoryError Simulator 1.0");  
  
              System.out.println("Author: Pierre-Hugues Charbonneau");  
  
              try {  
                     for (int i = 0; i < NB_ITERATIONS; i++) {  
                           String data = LEAKING_DATA_PREFIX + i;  
                      
                           // Add data to our leaking Map data structure...  
  
                           leakingMap.put(data, data);  
                     }  
  
              } catch (Throwable any) {  
  
                     if (any instanceof java.lang.OutOfMemoryError) {  
  
                            System.out.println("OutOfMemoryError triggered! "  
  
                                         + any.getMessage() + " [" + any + "]");  
                     } else {  
  
                           System.out.println("Unexpected Exception! " + any.getMessage()  
  
                                         + " [" + any + "]");  
                     }  
              }  
              System.out.println("simulator done!");  
  
       }  
}  

拿到内存溢出时的heapdump.hprof文件

    Eclipse中VM参数配置:在此我们把JVM堆的最大内存设置为20m,并且让程序运行过程中出现内存溢出的时候会dump当时的JVM对内存的内容,所以需要加上-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError。
在这里插入图片描述
① 运行示例代码即可生成Heap Dump文件。
在这里插入图片描述
② 一般在项目的当目前目录下。
在这里插入图片描述

导入heap文件分析

① 运行Memory Analyzer Tool。
在这里插入图片描述
② 报告分析:内存使用整体情况,直接点击下方的 Reports->Leak Suspects 链接来生成报告。
在这里插入图片描述
③ 查看导致内存泄露的罪魁祸首,从图上可以清晰地看到一个可疑对象消耗了系统近 98% 的内存。再往下看饼图下方文字简短描述了大量的内存是由属于Object实例的对象所消耗的,system class loader 负责加载这个对象。也许从这里还不能找出内存泄漏的具体原因,接着往下看。
在这里插入图片描述
④ 点击下图标志的地方。
在这里插入图片描述
⑤ 可以看到如下,鼠标点击圈红色的部分(即选择数值最大的那个Class Name)。
备注:
(1) Shallow Heap 为对象自身占用的内存大小,不包括它引用的对象。
(2) Retained Heap 为当前对象大小 + 当前对象可直接或间接引用到的对象的大小总和。
在这里插入图片描述
⑥ 鼠标点击圈红色的部分就会出现以下界面,逐个打开找到OOM的标志。
在这里插入图片描述

⑦ 此图展现了HashMap$ Entry被引用的路径,HashMap$Entry被一个java.util.HashMap的table实例变量引用,而这个HashMap又被JVMOutOfMemberyErrorSimulator类变量leakingMap引用,所以通过这些路径就很容易找到是哪段代码导致的内存溢出,然后更改代码就好。

三、总结

    通过以上分析我们就发现,类JVMOutOfMemberyErrorSimulator的leakingMap变量的内容太大导致了内存溢出,所以这样就能很快定位到问题。

发布了185 篇原创文章 · 获赞 457 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_42146366/article/details/105358432
今日推荐