[android]_[内存泄露分析和排查]

场景:1.app运行一段时间,会出现内存增大的情况

           2.执行某一个操作多次,会出现界面卡住或者界面变黑的情况

           3.加载大数据进行显示预览的时候

产生内存泄露的原因:

当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏。


1 内存泄漏的排查方法


Dalvik Debug Monitor Server (DDMS) 是 ADT插件的一部分,其中有两项功能可用于内存检查 :

·heap 查看堆的分配情况

·allocation tracker跟踪内存分配情况

DDMS 这两项功能有助于找到内存泄漏的操作行为。

Eclipse Memory Analysis Tools (MAT) 是一个分析 Java堆数据的专业工具,用它可以定位内存泄漏的原因。

工具地址 :

http://www.eclipse.org/mat/downloads.php

http://download.eclipse.org/mat/1.4/update-site/


1.1 观察 Heap

运行程序,然后进入 DDMS管理界面,如下:



 

首先要load出应用的内存快照,这里分为4步,第一步,选中我们要查看的应用,第二步点击Update Heap按钮,这时候DDMS就会通知应用准备收集内存信息,第三步选择Heap标签,heap标签页能够展示出内存的所有信息。第四步点击Cause GC,这时候就会把内存快照load出来。这样DDMS就把内存快照load出来了



Load出内存信息之后,选中data object这一行,就来分析我们应用中是否存在内存泄漏,
分析内存泄漏的关键的数据之一,就是Total Size。

主要关注两项数据:

(1) Heap Size 堆的大小,当资源增加,当前堆的空余空间不够时,系统会增加堆的大小,若超过上限 (例如64M,视平台和具体机型而定)则会被杀掉

(2)  Allocated 堆中已分配的大小,这是应用程序实际占用的内存大小,资源回收后,此项数据会变小

·        查看操作前后的堆数据,看是否有内存泄漏
对单一操作(比如添加页,删除页)进行反复操作,如果堆的大小一直增加,则有内存泄漏的隐患。



1.2使用内存工具MAT分析

有关MAT的具体概述

http://www.importnew.com/2433.html

1.2.1 使用OverView观察内存使用情况

DDMS 可以将当前的内存 Dump成一个 hprof格式的文件,MAT 读取这个文件后会给出方便阅读的信息,配合它的查找,对比功能,就可以定位内存泄漏的原因。

·        获取 hprof文件

点击工具栏上的  按钮,将内存信息保存成文件。 如果是用 MAT Eclipse 插件获取的 Dump文件,则不需要经过转换,Adt会自动进行转换然后打开。

刚刚开始启动程序,监听下堆大小的情况,如下图所示:

点击按钮,查看内存使用分配情况


以上是程序没有执行任何操作时,堆的内存使用情况。

下面是代码操作示例

static class Key {
		  private String key;

		  public Key(String key) {
		   this.key = key;
		  }
	}
	public static long getFreeMemory() {
		  return Runtime.getRuntime().freeMemory() / (1024 * 1024);
		 }
	
	
	public void TestStringAndList(){
		
		Map<Key, String> map = new HashMap<Key, String>(1000);
		int counter = 0;
		while (true) 
		{
			map.put(new Key("how do you do dummyKey"), "value");
			counter++;
			if (counter % 1000 == 0) {
			    System.out.println("map size: " + map.size());
			    System.out.println("Free memory after count " + counter
			    		+ " is " + getFreeMemory() + "MB");
			 } 
		}
	}
	
代码中反复执行向map中添加数据,检测堆的内存使用情况,如下

没有执行任何操作之前:


反复执行示例代码操作之后:


两个比较

Heap Size 堆的大小,反复执行代码操作之后,内存一直增加。

Allocated 堆中已分配的大小,没有随资源回收而变小。

使用MAT工具进行分析hprof文件

启动程序没有执行任何操作之前:

反复执行示例代码操作之后:


两个图进行比较,这样很快就可以找出是那个位置出现了内存泄露,然后我们就直接分析内存增大的模块的详细信息。

下面我们拿(d)和(e)进行分析找出内存泄露的位置

(d)-->对应Problem Suspect4 直接点开detail显示内存泄露的详细,我们只要看有小圆点的地方,如下:


点击小圆点的内存地址,会弹出一个菜单,选择“List Objects”>with incoming refs 将列出该类的实例:

选中 24 200这一行,右键Path to GC Roots-->exclue all phantom/weak/soft etc. reference :


从上图中我们可以看出String在使用的时候,出现OutOfMemeryError,从这个地方我们可以找出是代码中使用String字符串造成内存增大,导致内存泄露。

(d)-->对应Problem Suspect5 直接点开detail显示内存泄露的详细,我们只要看有小圆点的地方,如下:


点击小圆点的内存地址,会弹出一个菜单,选择“List Objects”>with incoming refs 将列出该类的实例:

选中11496 11496或者29256 29256其中某一行,右键Path to GC Roots-->exclue all phantom/weak/soft etc. reference :

我们大致可以找到原因,使用自定义的静态类Key不正确。

1.2.2 通过Histogram观察内存使用情况

直方图(Histogram)

MAT最有用的工具之一,它可以列出任意一个类的实例数。查找内存泄露或者其他内存方面问题是,首先看看最有可能出问题的类,这个类有多少个实例是个比较好的选择。它支持使用正则表达式来查找某个特定的类,还可以计算出该类所有对象的保留堆最小值或者精确值。

1.计算保留堆大小

     a) 计算保留堆最小值(Calculate Minimum Retained Size) –计算保留堆最小值,并显示在表格中.
     b) 计算保留堆精确值(Calculate Precise Retained Size) – 计算保留堆精确值(这个过程需要一点时间) 并且显示在表格中.

2.正则表达式(Regex pattern) – 让用户查询某个特定的对象类

我们可以选择堆大小较大的几个实例数进行内存泄露的检查分析,比如查看type[]

选中byte[]行,右键选择“List Objects”>with incoming refs 将列出该类的实例:


图中有小圆点的地方,代表这个位置有内存泄露,我们可以将其展开进行更加详细的查看,选择mBitmap进行查看,直接右键

Path to GC Roots-->exclue all phantom/weak/soft etc. reference :

在这里我们可以根据图片进一步分析使用什么导致内存泄露。

下面总结一下其他情况造成内存泄露

1.单例模式的使用

2.非静态内部类创建静态实例造成的内存泄漏

3.Handler造成的内存泄漏

4.线程造成的内存泄漏

5.资源未关闭造成的内存泄漏
对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。


具体代码实例看这里:

http://android.jobbole.com/82198/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值