Android内存优化方法——以Handler内存泄漏为例

问题

我们都知道移动设备因为各种原因,给应用分配的资源都有限,为了能够在有限的资源下实现更多的功能,我们必须管理好应用的内存。本文主要通过AndroidStudio和MAT(Memory Analyzer)来介绍检查内存泄漏的问题。

分析

大家都听说过Handler的内存泄漏,也有一些人对内存泄漏发生的原因和解决办法都很清楚,这里主要介绍MAT的使用和分析过程。
我们模拟一个耗时的数据取得过程,然后设置给TextView。

package com.frank.handlerleak;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;

public class MainActivity extends Activity {

    private android.widget.TextView textView;
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.textView = (TextView) findViewById(R.id.textView);
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                textView.setText("hello world!");
            }
        }, 99999999);
    }
}

把代码运行起来之后,把手机的屏幕旋转打开,我们利用屏幕旋转时Activity会重建来做文章。重复旋转屏幕5到10次。


在AndroidStudio的AndroidMonitor里边点击Monitors,然后找到红框里边的东西。左边的是手动触发GC回收,右边的是dump hprof。一般为了准确性,最好点下左边的触发一下GC。右边点击之后打开Captures。刚才dump的文件就在这里。

Android内存优化方法——以Handler内存泄漏为例_第1张图片

然后右键这个文件把它转化成标准的hprof,自己选择保存目录。


Android内存优化方法——以Handler内存泄漏为例_第2张图片

然后打开MAT,用它打开刚才的文件。

Android内存优化方法——以Handler内存泄漏为例_第3张图片

打开OQL,执行命令 select * from instanceof android.app.Activity 得到


Android内存优化方法——以Handler内存泄漏为例_第4张图片

说明内存种存在11个MainActivity的实例,有10个应该是被回收的,但是没有回收,这就是内存泄漏。

Android内存优化方法——以Handler内存泄漏为例_第5张图片

选这个,把软引用,弱引用和虚引用去掉。

Android内存优化方法——以Handler内存泄漏为例_第6张图片

我们看这两个,MainActivity是被this$0引用的,然后又被Message的callback引用,然后又到了MessageQueue上边。正是我们的Handler和Message问题(请参阅 Handler机制——Handler,Message,MessagQueue,Looper)。

那么我们应该如何解决了,在这里推荐一种非常简单的方法,那就是在Activity的onDestory里边调用Handler的removeCallbacks。
代码如下

package com.frank.handlerleak;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;

public class MainActivity extends Activity {

    private android.widget.TextView textView;
    private Handler handler = new Handler();
    private Runnable r;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.textView = (TextView) findViewById(R.id.textView);
        r = new Runnable() {
            @Override
            public void run() {
                textView.setText("hello world!");
            }
        };
        handler.postDelayed(r, 99999999);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacks(r);
    }
}

重复上边的操作,再来看一下内存的情况。

Android内存优化方法——以Handler内存泄漏为例_第7张图片

现在只有一个MainActivity的实例了。内存泄漏解决了。
当然还有其它办法来解决Handler的内存泄漏,这里就不再解释了,重点是使用工具来检查自己应用中的内存情况来优化内存管理。

你可能感兴趣的:(Android内存优化方法——以Handler内存泄漏为例)