zoukankan      html  css  js  c++  java
  • 一次使用Eclipse Memory Analyzer分析Tomcat内存溢出(转)

    前言

    在平时开发、测试过程中、甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序有严重的问题。我们需要找造成OutOfMemoryError原因。一般有两种情况:

    1、内存泄露,对象已经死了,无法通过垃圾收集器进行自动回收,通过找出泄露的代码位置和原因,才好确定解决方案;
    2、内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况。
    以上是处理Java堆问题的思路,具体是怎么进行分析,这里介绍的是使用Eclipse Memory Analyzer tool(MAT)工具分析的过程。
     

    生成dump文件

         通过jvm参数--XX:-HeapDumpOnOutOfMemoryError可以让JVM在出现内存溢出是Dump出当前的内存转储快照;
         或者,用jmap生产dump文件,win通过任务管理器查看tomcat的进程pid,linux用ps命令查看进程pid,然后用jmap命令(Java5:jmap -heap:format=b <pid>;Java6:jmap -dump:format=b,file=HeapDump.bin <pid>)。
        
         我这里使用的是,我一生产环境项目,运行一段时间大概3周的样子,就会报OutOfMemoryError。(ps:这个项目出现这种情况已经有好长一段时间了,我们之前的做法是定期的重启tomcat,没有去分析它的原因。)JDK64位主要参数:-Xmx3078M -Xms3078M -XX:PermSize=1024M -XX:MaxPermSize=1024M,内存还是蛮大的。
     
     

    MAT安装与介绍
         下载地址:http://www.eclipse.org/mat/downloads.php。
         通过MAT打开dump出来的内存文件,打开后如下图:

         
         从上图可以看到它的大部分功能。
         1. Histogram可以列出内存中的对象,对象的个数以及大小。
         2. Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
         3.Top consumers通过图形列出最大的object。
         4.Leak Suspects通过MA自动分析泄漏的原因。
        
         Histogram如下图:
         Objects:类的对象的数量。
         Shallow size:就是对象本身占用内存的大小,不包含对其他对象的引用,也就是对象头加成员变量(不是成员变量的值)的总和。
         Retained size:是该对象自己的shallow size,加上从该对象能直接或间接访问到对象的shallow size之和。换句话说,retained size是该对象被GC之后所能回收到内存的总和。
         我们发现ThreadLocal和bingo.persister.dao.Daos类的对象占用了很多空间。


     
         Dominator Tree如下图:
         我们发现quartz的定时器的工作线程(10个)占了很多的内存空间


     
         Top consumers如下图:
         这里显示了内存中最大的对象有哪些,他们对应的类是哪些,类加载器classloader是哪些。
         有些时候,我们在这里就可以看到代码泄露的位置。



     
         Leak Suspects如下图:
         从那个饼图,该图深色区域被怀疑有内存泄漏,可以发现整个heap才250M内存,深色区域就占了34%。后面的描述,告诉我们quartz线程占用了大量内存,并指出system class loader加载的"java.lang.ThreadLocal"实例的内存中聚集(消耗空间),并建议用关键字"java.lang.ThreadLocal$ThreadLocalMap$Entry[]"进行检查。所以,MAT通过简单的报告就说明了问题所在。



     
    通过Leak Suspects的Problem Suspect 1点击【Details »】,
    如下图如下图所示的上下文菜单中选择 List objects -> with outgoning references, 查看ThreadLocal都应用了些什么对象。




     
    现在看到ThreadLocal中引用的对象如下图:
    是dao对象
    ps:该dao对象包含一个轻量级的ORM关系内容,所以Retained size比较大



    下面继续查看dao的gc ROOT
    如下图所示的上下文菜单中选择 Path To GC Roots -> exclude weak references, 过滤掉弱引用,因为在这里弱引用不是引起问题的关键。
     


     
     
    从下图中,可以看到在org.quartz.simpl.SimpleThreadPool中保存了daos的引用。所以可以得出是是因为定时器在运行的过程中持有大量的Daos对象应起了内存泄露。为什么会有那么多的Daos呢,Daos不是一个无状态的单例的、可以重用的吗?继续查看spring配置文件发现Daos的bean配置成scope="prototype",导致定时任务又是每次调用都生产新的Daos实例。由于是Daos是无状态的,修改为单例的,问题解决。
     



    以上是通过MAT分析Tomcat应用程序,找到内存泄露的原因,并解决。
  • 相关阅读:
    WCF Server Console
    Restart IIS With Powershell
    RestartService (recursively)
    Copy Files
    Stopping and Starting Dependent Services
    多线程同步控制 ManualResetEvent AutoResetEvent MSDN
    DTD 简介
    Using Powershell to Copy Files to Remote Computers
    Starting and Stopping Services (IIS 6.0)
    java中的NAN和INFINITY
  • 原文地址:https://www.cnblogs.com/suifengbingzhu/p/4927866.html
Copyright © 2011-2022 走看看