AndroidStudio + MAT 内存泄漏分析

一概要:

内存泄漏是一些已经不使用的对象,依然占有内存且垃圾回收机制不法回收它们。最终导致常驻内存越来越大

,影响到程序的性能。

在Android 虚拟机中,采用Mark-Sweep方式实现垃圾回收。Mark标记,Sweep检测。虚拟机会从GC Roots开始

遍历,如果某个节点无法找到一条到达GC Roots的路径,则表示该引用无效,可以被回收。内存泄漏就是存在一些

不好的调用,导致一些无效的引用于GC Roots相连,无法被回收。

知道了原因,我们理应在开发中尽量避免这些。但是万一发生了(代码又不是一个人写的),我们要准确找出它们。

所以我们就要用到检测内存泄漏的工具。

转载:http://blog.csdn.net/u012760183/article/details/52068490

二使用:

实例代码(我们进入主页面后,点击启动TestSecondActivity,然后按返回退出):

   Intent intent2 = new Intent(MainActivity.this, TestSecondActivity.class);
   startActivity(intent2);

public class TestSecondActivity extends AppCompatActivity{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_testsecond);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                LogUtil.i("TestSE", "thread:" + Thread.currentThread() + "start");
                try{
                    Thread.sleep(80000l);
                }catch (Exception e){

                }
                LogUtil.i("TestSE", "thread:" + Thread.currentThread() + " end");
            }
        };
        new Thread(runnable).start();
    }
}

我们会通过两种方式,来检测内存泄漏:

#使用MAT用具查找

1,首先打开Android Studio中的Android Device Monitor如下图。


2,打开后会出现下面界面,选中你要检测应用的包名,然后点击下图画圈的地方(Update Heap),会在程序包

名后标记一个图标


3,接下就是我们的操作,,重复启动回退TestSecondActivity 两次,然后再点下图画圈地方(Dump HPROF file)

生成hprof文件。


生成的hprof文件。


4,因为MAT是用于分析java hprof的工具,我们生成的是Android属性的hprof文件,所以我们要转化一下(我将刚刚

生成的文件重名android.hprof)。

Android Sdk中为我们提供了工具:hprof-conv.exe。


转化成了java属性的文件java.hprof。

5,使用MAT打开hprof文件,(如果还没有安装MAT的,先下载安装:https://www.eclipse.org/mat/)。


打开后如图:


6,之后我们查看内存中的对象,由于我们的内存泄漏一般都发生在Activity中所以我们之查找Activity即可。

点击下图中的QQL图标,输入select * from instanceof android.app.Activity,类似于SQL语句。红色感叹号为执行按钮。

#内存中有两个TestSecondActivity,但是我们已经退出了TestSecondActivity,说明发生了内存泄漏。

#上面有两个属性。Shallow Size对象自身占用大小,不包括引用。Retained Size对象自身大小+ 直接或间接引用对象

的大小。

7,右击TestSecondActivity,—— Path to GC Roots——All Reference。


看到this$0引用了这个Activity,this$0表示内部类意思。Activity被一个内部类引用,而这个内部类又被target(Thread)引用。

从上面的代码可知:

TestSecondActivity中有内部类runnable,而runnable被Thread使用。工作线程Thread需要sleep 80秒。所以导致

TestSecondActivity无法释放。

解决方法。我们在Activity onDestroy中shutdown 线程Thread就可以了(当然先把Thread变成全局变量)

#直接使用Android Studio上的Monitor Memory查找

1,依然是利用上面的代码,运行程序,打开Android Studio的Monitor界面,查看Memory图像。


2,点击下卡车图标(图中1),可以执行一次GC;点击图中2的位置,可以查看hprof文件。(依次点击1,2)

3,查看结果


#同样监听到了TestSecondActivity的内存泄漏。

三注意

Android中内存引起内存泄漏的常见使用。

1,static变量引起的内存泄漏。

因为static生命周期是类加载时开始,类卸载结束。也就是说static变量在程序死亡时才结束。而如果static变量引用

Activity,那么Activity的资源将一直得不到释放。造成内存泄漏。

解决方法,如果需要Context对象,尽量使用getApplicationContext。假如必须使用Activity那么最好在onDestroy方

法中,将Activity引用设置为null。

2,线程造成的内存泄漏。

类似于上面的例子,线程执行时间长,即使Activity结束了任然在执行。因为new Thread生成一个匿名内部类(内部

类的创建必须依靠外部类),因此握有Activity实例,Activity无法释放。AsyncTask更为严重,因为AsyncTask维持一

个生命周期。

解决方法:合理安排线程,控制线程在Activity结束时结束。

3,Bitmap占用过多的内存。

Bitmap解析需要占用内存,但是Android只提供了8M内存给Bitmap,如果Bitmap过多且不能及时的回收。则会造成内

存溢出。

解决方法:及时recycle,加载图片前先适当的压缩图片。

4,资源未被及时关闭造成内存泄漏

例如Cursor,没有及时关闭,会因持有Activity引用,造成内存泄漏。

解决方法:在onDestroy中及时的关闭。

5,Handler的使用

Handler对象会发送Message到MessageQueue,Looper对象会轮询MessageQueue对象去除Message执行。如果

Message对象长时间未被取出执行。则Message对象持有Handler对象,Handler对象持有Activity(可能)。造成泄漏。

解决方法,在onDestroy中,Handler removeMessage。


欢迎指正!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值