【Android程序优化,避免内存泄露】- [实战一]:避免内存泄露的最后一道墙,使用leakcanary分析程序中的内存泄露。

转载 2016年08月29日 22:53:01

前言:

打算写一个系列吧,包括程序怎么优化,如何避免内存泄露,出现内存泄露该如何处理分析。

这个系列应该会很长,首先会根据实际项目中遇到的东西总结整理上来,然后会收集网上相关好资源分享。

内容大致分两种,一种是[实战N]开头,都是可以直接拿来用的,可能比较少甚至没有理论内容。

另一种以初步拟定以[理论/原理N]开头,会解释介绍一些内存泄露,javaGC原理等内容。使大家知其然知其所以然。

当然希望大家看后有疑问、不同观点等尽量及时指出,多多交流。


正文:


一、避免内存泄露的最后一步,找出程序中的内存泄露:


感觉本系列的开篇第一篇反而最后一步,最后一道墙。(你就当我这是电影里的倒叙吧)。
即,程序已经发生了内存泄露甚至导致内存溢出OOM,需要迅速定位问题点,以便分析解决。(其实就是今天我们即将上线的app发生的情况),
我觉得这也是大部分APP都会遇到的情况,现在我也不想听那么多理论原因了,我就知道我的程序卡死了,看LOG出现了Out Of Memory的ERROR,
该如何定位分析问题呢?
我们今天的猪脚就出现了,即LeakCanary!内存泄露分析利器。
又是Square公司出品的,他们公司出过啥?OkHttp,Picasso.................反正各个精品,掉渣天,不多废话了。
首先,这里是leakcanary的github地址:
https://github.com/square/leakcanary。

使用步骤:

1、在build.gradle里添加如下引用:(截止20160329最新版本)
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' // or 1.4-beta2
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // or 1.4-beta2
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // or 1.4-beta2


2、在程序的Application类里添加如下代码:
public static RefWatcher getRefWatcher(Context context) {
    LeakDemoApplication application = (LeakDemoApplication) context.getApplicationContext();
    return application.refWatcher;
}

private RefWatcher refWatcher;

@Override
public void onCreate() {
    super.onCreate();
    refWatcher = LeakCanary.install(this);
}
即在Application的onCreate()方法里,调用LeakCanary.install(this)方法,得到方法返回的RefWatcher对象,用于给其他Activity监控内存泄露使用。


3、在需要被监控的Activity、Fragment里的onDestroy()方法里添加如下代码:
3.1,如果是Activity的话:
@Override
protected void onDestroy() {
    super.onDestroy();
    /**
     * 在Activity的onDestroy()里添加如下代码即可对该Activity的内存泄露问题进行监控。
     * 一般我们的项目都会有一个BaseActivity,在BaseActivity里onDestroy()方法里添加如下代码即可监控该App所有的Activity的内存泄露问题。
     */
    RefWatcher refWatcher = LeakDemoApplication.getRefWatcher(this);
    refWatcher.watch(this);
}
3.2,如果是Fragment的话:
@Override
public void onDestroy() {
    super.onDestroy();
    RefWatcher refWatcher = LeakDemoApplication.getRefWatcher(getActivity());
    refWatcher.watch(this);
}
他们监控的都是Activity.


4、经过以上三步,集成已经完毕,编译运行代码即可。

接着我们使用我们的app,进行正常的测试debug操作,如果某个Activity有内存泄露,在Activity切换时,会弹出提示,如下:


然后经过10s左右的延时,在状态栏上也可以看到提示,如下:


此时点击状态栏通知即可查看具体的内存泄露是何问题:


由上图可以清晰的看出内存泄露发生在哪里,以及相关对象的持有引用链(从上至下)。这里是由于我们项目的一个Banner广告轮播控件在Activity销毁时没有停止播放造成的。


二、注意事项:

1、目前leakcanary一次只能在一个Activity中检测出一个内存泄露问题,所以如果你的Activity有多个内存泄露问题,需要先将这个问题解决掉,然后再次运行测试,切换Activity,查看有无剩余的内存泄露问题。切记不要以为解决了一个内存泄露提示,你的Activity就没有问题了,今天下午我们的app某个Activity最多有三个内存泄露问题。



三、一个简单Demo:

核心Activity类:
package mcxtzhang.leakdemo;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.squareup.leakcanary.RefWatcher;

/**
 * Created by zhangxutong .
 * Date: 16/03/29
 */
public class LeakActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        /**
         * 在Activity的onDestroy()里添加如下代码即可对该Activity的内存泄露问题进行监控。
         * 一般我们的项目都会有一个BaseActivity,在BaseActivity里onDestroy()方法里添加如下代码即可监控该App所有的Activity的内存泄露问题。
         */
        RefWatcher refWatcher = LeakDemoApplication.getRefWatcher(this);
        refWatcher.watch(this);

        /**
         * 非静态内部类Handler内存泄露解决方法:
         */
        if(mLeakHandler.hasMessages(MSG_LEAK_DELAY)){
            mLeakHandler.removeMessages(MSG_LEAK_DELAY);
        }
        //或者使用如下语句,移除所有此Handler里未被执行的CallBack和Message
        //mLeakHandler.removeCallbacksAndMessages(null);
    }

    /**
     * 下面的是一个典型的内存泄露实例:
     * 即一个非静态内部类Handler中有未来得及处理或者延时处理的消息,
     * 但是此时该Activity退出了,并没有移除Handler中未处理的消息,会造成内存泄露。
     * 解决方法是,
     * 一:将此Handler改写为静态内部类,并使用WeakReference弱引用来引用Activity对象。
     * 二(推荐):在Activity的onDestroy()方法里移除未处理的消息。
     * 原因是:非静态内部类会持有外部类的引用:
     * 持有关系大致为:Looper-MessageQueue-Message-Handler-Activity
     */
    private static final int MSG_LEAK_DELAY = 1;
    private Handler mLeakHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //do sth
            Log.d("zxt", "handleMessage() called with: " + "msg = [" + msg + "]");
        }
    };

    public void onLeakClick(View v) {
        Toast.makeText(this, "已经成功产生一个内存泄露,现在退出此Activity试试看。", Toast.LENGTH_SHORT).show();
        mLeakHandler.sendEmptyMessageDelayed(MSG_LEAK_DELAY, 1000000);
    }
}



四、参考文献和本文Demo下载地址:

本文demo下载地址:

http://download.csdn.net/detail/zxt0601/9476104


参考文献:
http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
https://github.com/square/leakcanary

相关文章推荐

使用LeakCanary遇到的问题 就是不弹出来

今天楼主遇到引用LeakCanary时代码跟官网一样但是就不弹出来。楼主新建项目就可以正常使用。楼主郁闷半天,现在终于整出来了。 楼主主工程app引用module为thirdParty,本想为了整洁三...

【Android程序优化,避免内存泄露】- [实战一]:避免内存泄露的最后一道墙,使用leakcanary分析程序中的内存泄露。

前言: 打算写一个系列吧,包括程序怎么优化,如何避免内存泄露,出现内存泄露该如何处理分析。 这个系列应该会很长,首先会根据实际项目中遇到的东西总结整理上来,然后会收集网上相关好资源分享。 内容大致分两...

leakcanary分析内存泄露

  • 2016-03-30 00:17
  • 6.82MB
  • 下载

程序猿必知 — 避免android内存泄露的6条建议

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

用LeakCanary检查内存泄露Demo

  • 2017-03-20 19:58
  • 22.36MB
  • 下载

android 内存泄露分析 Lint StrictMode LeakCanary Memory Analyzer (MAT)

在安卓开发当中经常会碰到各种异常错误,尤其是OOM最让人恼火,接下来记录一下在日常开发中用到的几种帮助工具,能让我们更好地查找内存泄露出处。1.首先我们来找到内存泄露的定位:静态定位 静态代码的查找...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)