android内存分析

Mat的两张安装方式:


一、Eclipse在安装界面中安装

1、  在http://www.eclipse.org/mat/downloads.php中根据操作系统版本下载相应安装包;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

 

2、  下载相应安装压缩包后,对压缩包进行解压;本次测试的机器为Windows Server 2003 64位操作系统,为此下载的包为:MemoryAnalyzer-1.1.0.20110523-win32.win32.x86_64.zip。此安装包解压后路径为:

E:\TDDOWNLOAD\MemoryAnalyzer-1.1.0.20110523-win32.win32.x86_64\matMemoryAnalyzer-1.1.0.20110523-win32.win32.x86_64

3、  如果你需要用 MAT 来分析 IBM JVM 生成的 dump 文件的话,还需要额外安装 IBM Diagnostic Tool Framework

4、  点击MemoryAnalyzer.exe文件MemoryAnalyzer.exe启动后,点击Help---Check for Updates

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

5、  出现如下对话框,点击YES;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

6、   点击如下对话框中的Add;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

7、  点击Archive…后,选择在http://www.ibm.com/developerworks/java/jdk/tools/dtfj.html

中下载的dtfj-updatesite.zip文件的路径,选择后点击打开;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

8、  选择OK;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

9、  选择OK;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

10、Help---Install New Software…;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

11、按如下方式安装IBM Diagnostic Tool Framework;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

12、选择JVM-based Tools--- Diagnostic Tool Framework后,选择next;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

13、选择next;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

14、选择I accept …….后,再点击finish;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

15、安装过程出现如下对话框,点击OK;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

16、点击Restart Now;

17、重新启动后,点击help―――adbout Eclipse Memory Analyzer

18、点击installation details

19、如下图片显示安装成功;

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

点击close后―――点击Open a heap dump―――选择IBM JVM 生成的 dump 文件

Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 

如下为使用Eclipse Memory Analyzer分析得出的结果:

 


Eclipse Memory Analyzer使用心得 - love-888888 - 涂志勇的博客

 


二、复制文件的方式安装

第一步:下载Eclipse MAT

下载地址:http://www.eclipse.org/mat/downloads.php

第二步:下载之后将压缩包解压,放置到Myeclipse 的\MyEclipse 9\dropins目录下

解压后会看见这些文件: 纠正下面一个错别字不是"写"是 "下"

第三步:按照下图,A,B,C的顺序进行对应的文件的创建

第四部:重启Myeclipse,打开Window->Perferences,你会看见这个项目:


简单的说一下使用(控制台的)如果是tomcat或者是别的服务器需要你去查如何配置JVM参数:

以下是一个会导致java.lang.OutOfMemoryError: Java heap space的程序代码:(very easy)

[java]  view plain copy
  1. package org.lx.test;  
  2.   
  3. import java.util.Date;  
  4. import java.util.HashMap;  
  5. import java.util.Map;  
  6.   
  7. public class OutOfMemoryTest {  
  8.     public static void main(String[] args) {  
  9.         Map<Integer,Date> map=new HashMap<Integer, Date>();  
  10.         for (int i = 0; i < 600000000; i++) {  
  11.             map.put(i, new Date());  
  12.         }  
  13.     }  
  14.       
  15.       
  16. }  

首先在运行之前有一些参数需要设置:


然后就到了参数设置的页面,按照A,B的顺序设置参数:(-XX:+HeapDumpOnOutOfMemoryError)避免写错误可以copy

运行错误的程序代码会看见以下结果:

那么这时候就生成了一个文件java_pid3708.hprof,这个文件 在你的项目的根目录下(myeclipse10)

那么接下来我们就打开这个文件进行分析如何打开见下图:(选中刚刚在项目根目录下生成的文件java_pid3708.hprof打开)

打开之后你会看见下图就OK了:



至于这其中问题如何查找请参考以下连接:

以下文章已经说的非常详细了:

1.使用 Eclipse Memory Analyzer 进行堆转储文件分析

2.使用mat进行dump文件分析



MAT的使用



    一、准备工作
分析较大的dump文件(根据我自己的经验2g以上的dump文件就需要使用以下介绍的方法,不然mat会出现oom)需要调整虚拟机参数
找个64位的系统在memoryanalyzer.ini设置-xmx2g
如果是32位的xp可以使用下面的方法进行尝试:

  • 安装jrockit 6.0的jdk
  • mat使用jrockit的jdk来启动
    -vmd:/program files/java/jrockit-r28.0.0-jre1.6.0_17/bin/jrockit/jvm.dll-vmargs-xmx1700m


    二、开始使用mat进行oom分析
    第一步,启动mat ,选择file->open heap dump 选择你的dump文件。下面开始等待,mat解析dump文件需要花一些时间,在解析的同时会在硬盘上写入一些解析结果文件,这样下次打开时速度会快很多。有时候mat在解析过程中可能会出现出错的情况,这个时候可以将那些临时文件删除以后重试第一步,如果你的rp够好的话重试也许会解析成功。

    第二步,查看内存泄漏分析报表。mat解析完成以后会出现如下图的提示:

    因为我们就是为了查找内存泄漏的问题,所以保持默认选项直接点“finish”就可以。
    mat会非常直观的展现内存泄漏的可疑点,类似下面的报表可以直接看到某个线程占用了大量的内存

    问题的详细分析信息:


    第三步,开始寻找导致内存泄漏的代码点。这时往往需要打开对象依赖关系树形视图,点击如图按钮即可。

    这时会看到如下视图

    这个视图的左边大区域可以看到对象的依赖关系,选中某个对象以后可以在左边小窗口查看对象的一些属性。如果属性的值是一些内存地址你还可以点击工具栏的搜索按钮来搜索具体的对象信息。在进行具体分析的时候mat只是起了帮助你进行分析的工具的功能,oom问题分析没有固定方法和准则。只能发挥你敏锐的洞察力,结合源代码,对内存中的对象进行分析从而找到代码中的bug.



      android 内存溢出问题分析

           http://blog.csdn.net/com360/article/details/6682409

           避免Android内存泄露

           http://blog.csdn.net/xyz_lmn/article/details/7108011

           android中context及全局变量小析

           http://blog.csdn.net/aomandeshangxiao/article/details/7008636

           Android内存分析工具

           http://blog.csdn.net/sunboy_2050/article/details/7031234

           Android 官方博客 - Android应用程序的内存分析(翻译)

           http://dev.10086.cn/blog/?uid-13136-action-viewspace-itemid-9580

           在我参与的camera项目中,看log表面上是显示由于内存不足导致图片导入不进去,可是我对于程序中的bitmap都进行过释放,感觉这个不是根本原因,而且试过将代码中的context换成Application context,可还是于事无补,最后通过MAT工具发现是由于代码中通过handler发送的大量消息在程序结束时没有清除掉,导致一系列引用不能被释放。所以在这里也补充一点,handler发送消息没有回收也可能会导致内存溢出。下面就让我介绍下如何使用MAT来分析问题吧(由于机密问题,所以没有把自己代码的截图呈上,请见谅)

           1.用MAT打开转换好的prohf文件,如下图1所示


                                                                                                                                                                          图1

            2.选择工具栏中的“Open Dominator Tree for entire heap”,如下图2所示


                                                                                                                                                                  图2

            3.此时你会看到图中列出了一堆条目,而且很多都是你没见过或者不熟悉的,没关系,一般内存溢出都是由于我们自己写的代码导致的,所以先去找跟你包相关的条目,在这也说明下,往往这种操作很多次后才出现内存溢出的问题时,你会发现在图2中有很多相同的条目出现在一起,很可能问题就出在这里,所以先从这里下手,按照图2中的操作选择“exclude weak/soft references”,选择之后如下图3所示:


                                                                                                                                                                           图3

            4.同样在图3中,首先找跟你程序相关的条目然后一级一级的进入最终的跟路径,我们就能找到根本原因,是什么引用导致其他的一系列的资源不能被回收。在我的相机程序里最终发现是由于自己写的handler发送的消息在程序结束时一直没有清除,所以当我在程序中添加了mMainHandler.removeCallbacksAndMessages(null);问题就解决啦。。。



    在平时开发、测试过程中、甚至是生产环境中,有时会遇到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是无状态的,修改为单例的,问题解决。

     


     

    android里使用MAT

    1. 启动eclipse后,切换到DDMS透视图,并确认Devices视图、Heap视图都是打开的;
    2. 将手机通过USB链接至电脑,链接时需要确认手机是处于“USB调试”模式,而不是作为“Mass Storage”;
    3. 链接成功后,在DDMS的Devices视图中将会显示手机设备的序列号,以及设备中正在运行的部分进程信息;
    4. 点击选中想要监测的进程,比如system_process进程;
    5. 点击选中Devices视图界面中最上方一排图标中的“Update Heap”图标;
    6. 点击Heap视图中的“Cause GC”按钮;
    7. 此时在Heap视图中就会看到当前选中的进程的内存使用量的详细情况。
    说明:
    a) 点击“Cause GC”按钮相当于向虚拟机请求了一次gc操作;
    b) 当内存使用信息第一次显示以后,无须再不断的点击“Cause GC”,Heap视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化;
    c) 内存使用信息的各项参数根据名称即可知道其意思,在此不再赘述。
      如何才能知道我们的程序是否有内存泄漏的可能性呢。这里需要注意一个值:Heap视图中部有一个Type叫做data object,即数据对象,也就是我们的程序中大量存在的类类型的对象。在data object一行中有一列是“Total Size”,其值就是当前进程中所有Java数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。可以这样判断:
    a) 不断的操作当前应用,同时注意观察data object的Total Size值;
    b) 正常情况下Total Size值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况,所以说虽然我们不断的操作会不断的生成很多对 象,而在虚拟机不断的进行GC的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;
    c) 反之如果代码中存在没有释放对象引用的情况,则data object的Total Size值在每次GC后不会有明显的回落,随着操作次数的增多Total Size的值会越来越大,
      直到到达一个上限后导致进程被kill掉。
    d) 此处已system_process进程为例,在我的测试环境中system_process进程所占用的内存的data object的Total Size正常情况下会稳定在2.2~2.8之间,而当其值超过3.55后进程就会被kill。


            在Android 应用程序开发和调试过程中 OOM (out of memory)  错误是个十分常见的问题,相信大多数应用开发者都遇到过,此类问题多半是程序运行一段时间后突然出错,而且出错后 Force Close, 因此不易查找原因。今日在这里分享下自己的一些经验。

            从C++ 到 Java ,在面向对象编程的发展过程中,有了很大的进步。Java 引入了Garbage Collection 机制从而将程序开发者从繁琐的内存管理中解放出来,自此解决了C++中野指针和由于指向内存的指针丢失而造成的内存泄漏的问题。但是使用Java 就可随意使用内存不必担心内存泄漏的问题么? 显然不是。Garbage Collector 的职责是:1. 找到程序中不能再被访问的数据对象;2.释放这些对象占有的资源。所以看得出来Garbage Collector 回收内存的前提是对象已经不可访问(特殊类型的reference 不在内),逻辑上的内存泄漏(指向对象的引用没有被释放导致的内存泄漏)还是存在的。 

            解决这种逻辑上的内存泄漏关键是找到致使对象不能释放的引用链的始端,这个被称为GC Roots。熟悉java的朋友应该都知道有很多分析工具。因为本人是Android 开发对Java 不是很熟,所以只用过 Eclipse Memory Analyzer,在这里和大家分享一下。


    1. Eclipse Memory Analyzer :

    The  Eclipse Memory Analyzer is a fast and feature-rich heap analyzer that helps you find memory leaks and high memory consumption issues.

    2.安装:(直接作为Eclipse 的插件安装)

           Open   Help->Install New Software   Add this URL  http://download.eclipse.org/mat/1.1.0/update-site/ 

           如果安装成功可以看到一个图标 


    3.分析原理 :

    一个java heap dump 是某个时刻JVM中所有java 对象的一个镜像,而Eclipse Memory Analyzer 基于java heap dump 提供可视化的分析工具分析对象和引用存在情况。Eclipse Memory Analyzer 可以处理HPROF 格式的 heap dump. 


    4.Eclipse 可以将本地JVM 的heap dump 出来, 但是对于Android 则需要借助DDMS 将heap dump 出来。 如图(选择进程dump hprof file):




    4.选择一下Leak Suspect Report




    5.点选 Dominator Tree 查看对象列表




    6.Dominator  Tree 可以看到所有对象,最上面一行可以用正则,用来找到我们感兴趣的类和对象。




    7.还可以对它们进行分组:










    8.选择泄漏的对象,右键点击,可以容易的找到GC roots ,然后就容易分析这个引用为什么还指向这个对象致使它不能被回收了。




    9.Eclipse Memory Analyzer 还有一个更强的功能就是对比不同的heap dumps, 试想如果你想对比几个不同时刻JVM 中java 对象的状态,你就会感觉这个工具特别好用。首先用DDMS dump 出heap,然后再Dominator Tree 视图 按包名分组,然后右击要分析的包,选择“Show Retained Set” 




    10.打开导航视图:(Window->showWindow->Other->Memory Analyzer Views->Navigation History) 




    11.在导航视图中,点击刚才选择的包,右击选择"Add to Compare Basket" ,然后即可以在Compare Basket 中看到了。 




    12.对几次不同的dump 重复进行上面的操作,看到Compare Basket 里面已经有了几次不同的记录,然后选择记录,右击,选择“Compare Tables with all set operations” 


      


    13.然后就可以看到对象对比了:




    13.还可以选择百分比视图:




    14.分析GC roots :





    15. 参考资料:





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值