How to check memory leaks in android app?

什么是内存泄漏?
有些对象只有有限的生命周期。当它们的任务完成之后,它们将被垃圾回收。如果在对象的生命周期本该结束的时
候,这个对象还被一系列的引用,这就会导致内存泄漏。持续累加,内存很快被耗尽。
比如,当
Activity.onDestroy 被调用之后, activity 以及它涉及到的 view 和相关的 bitmap 都应该被回收。但是,如果
有一个后台线程持有这个
activity 的引用,那么 activity 对应的内存就不能被回收。这最终将会导致内存耗尽,然后因
OOM crash
内存泄漏造成什么影响?
它是造成应用程序
OOM 的主要原因之一。由于 android 系统为每个应用程序分配的内存有限,当一个应用中产生的内存
泄漏比较多时,就难免会导致应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用
Crash
什么是
LeakCanary
leakCanary Square 开源框架,是一个 Android Java 的内存泄露检测库,如果检测到某个 activity 有内存泄露,
LeakCanary 就会自动地显示一个通知,所以可以把它理解为傻瓜式的内存泄露检测工具。通过它可以大幅度减少开发
中遇到的
OOM 问题,大大提高 APP 的质量。
关于
LeakCanary 的一些介绍可以参考如下链接:
LeakCanary: 让内存泄露无所遁形

LeakCanary 中文使用说明



LeakCanary 是 Android 和 Java 内存泄露检测框架,该框架是Square公司的一个开源库,项目地址 leakcanary

Android 开发中你是否频频遇到内存泄露而无奈无从解决。说不定哪天你不小心写的一行代码就导致了内存泄露。可以先看看这些问题导致的内存泄露 Android开发编码规范导致的内存泄露问题,而LeakCanary 则很直白得检测出了内存泄露并展示给我们。在使用它之前,我们来写一个例子。

本地广播,在开发中还是有一定的应用的,现在有这么一个需求,要求使用本地广播来实现,就是通过发送一个退出程序的本地广播,所有Activity接收到后就退出,这显然是需要一个基础的Activity,其他Activity继承它。为了方便,这里我们只使用一个Activity。

[java]  view plain  copy
  1. public class MainActivity extends AppCompatActivity {  
  2.     public final static String ACTION_EXIT_APP = "cn.edu.zafu.leakcanary.exit";  
  3.     private static LocalBroadcastManager mLocalBroadcatManager;  
  4.     private BroadcastReceiver mExitReceiver = new BroadcastReceiver() {  
  5.   
  6.         @Override  
  7.         public void onReceive(Context context, Intent intent) {  
  8.             String action = intent.getAction();  
  9.             if (action.equals(ACTION_EXIT_APP)) {  
  10.                 Log.d("TAG""exit from broadcast");  
  11.                 finish();  
  12.             }  
  13.         }  
  14.     };  
  15.     @Override  
  16.     protected void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.activity_main);  
  19.         init();  
  20.     }  
  21.   
  22.     private void init() {  
  23.         IntentFilter filter = new IntentFilter();  
  24.         filter.addAction(ACTION_EXIT_APP);  
  25.         filter.addCategory(Intent.CATEGORY_DEFAULT);  
  26.         getLocalBroadcastManager().registerReceiver(mExitReceiver, filter);  
  27.     }  
  28.   
  29.     private  LocalBroadcastManager getLocalBroadcastManager() {  
  30.         if (mLocalBroadcatManager == null) {  
  31.             mLocalBroadcatManager = LocalBroadcastManager.getInstance(this);  
  32.         }  
  33.         return mLocalBroadcatManager;  
  34.     }  
  35.   
  36. }  

乍一看,是不是感觉写的很对啊,那你就不够细心了,这还是少量的代码,对于项目中日积月累的代码,内存泄露或许无处不在。我们使用LeakCanary 对我们的代码进行检测下,看看到底哪里发生了内存泄露,以及该如何解决。

使用方法也很简单,首先加入依赖

[java]  view plain  copy
  1. debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'  
  2. releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'  

从依赖中也是可以看出猫腻的。

然后在我们程序的Applictaion中进行安装,当然,不要忘记在清单文件中注册该Application。

[java]  view plain  copy
  1. public class App extends Application {  
  2.     @Override  
  3.     public void onCreate() {  
  4.         super.onCreate();  
  5.         LeakCanary.install(this);  
  6.     }  
  7. }  

我说就这么简单你会信,好了,我们安装到手机上看看。安装完成后运行该软件,打开后退出该软件,这时候你发现桌面上多了一个Leaks的图标。

这里写图片描述

打开它后通知栏会有一个通知,通知你发生了内存泄露

这里写图片描述

然后在软件里你会看到内存泄露的跟踪信息。

这里写图片描述

点击下方的delete可以删除此条信息。

仔细一看,原来是我们的mLocalBroadcatManager发生了泄露,注册本地广播的时候,传入了this,系统内部保持了这个引用,当我们退出Activity时,这个引用还是指向我们的Activity,导致Activity回收失败。那么怎么解决了,既然退出的时候还持有引用,那么我们取消注册这个广播这个引用不就没了吗,重写onDestroy方法,进行取消注册。

<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onDestroy</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onDestroy(); getLocalBroadcastManager().unregisterReceiver(mExitReceiver); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

重新运行一下,咦,你发现内存不再泄露了。该软件里不再提示内存泄露的跟踪信息了。

这里写图片描述

就是这么简单,如果想更进一步了解使用方法,比如检测Fragment有没有泄露。可以参考官方给的例子,并且内存泄露的跟踪信息也是可以上传到服务器的,更多内容,参考 leakcanary

源码下载


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值