以前用eclipse的时候,我们采用的是DDMS和MAT,不仅使用步骤复杂繁琐,而且要手动排查内存泄漏的位置,操作起来比较麻烦。后来随着Android studio的潮流,我也抛弃了eclipse加入了AS。

Android Studio也开始支持自动进行内存泄漏检查,并且操作起来也比较方便。

我们大家都知道,系统是不可能将所有的内存都分配给我们的应用程序的。每个程序都会有可使用的内存上限,这被称为堆大小(Heap Size)。不同的手机,堆大小也不尽相同,随着现在硬件设备不断提高,堆大小也提升了。如果大家想要知道自己手机的堆大小是多少,可以调用如下代码:

ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
int heapSize = manager.getMemoryClass();

结果是以MB为单位进行返回的,我们在开发应用程序时所使用的内存不能超出这个限制,否则就会出现OutOfMemoryError。因此,比如说我们的程序中需要缓存一些数据,就可以根据堆大小来决定缓存数据的容量。

下面介绍下采用Android Studio Monitor来检测内存泄漏,栗子如下:

每次启动MainActivity中时都会调用一个线程,然后这个线程会执行runnable的run方法 由于Runnable是一个匿名内部对象 所以握有MainActivity的引用,因此 
连续启动MainActivity 4次,最后退出。按照常理来说,MainActivity会被销毁回收,可实际可能并不是这样。

打开Android Studio,编译代码,在模拟器或者真机上运行App,在Android Monitor下点击Monitor对应的Tab,进入如下界面

 

在Memory一栏中,可以观察不同时间App内存的动态使用情况,点击可以手动触发GC,点击可以进入HPROF Viewer界面,查看Java的Heap,切换到Package Tree View,方便查看,点击Analyzer Task,Android Monitor就可以为我们自动分析泄漏的Activity,如下图

Reference Tree代表指向该实例的引用,可以从这里面查看内存泄漏的原因,Shallow Size指的是该对象本身占用内存的大小,Retained Size代表该对象被释放后,垃圾回收器能回收的内存总和。

看上图,左边是内存中的对象,右边还存在4个MainActivity实例,我们明明是全部退出的,怎么还存在,这表明出现了内存泄露。

我们查看Reference Tree, 看到 this$0引用了这个MainActivity而this$0是表示内部类的意思,也就是一个内部类引用了MainActivity 而 this$0又被 target引用, target是一个线程。内存泄漏的原因就是MainActivity被内部类引用,而内部类又被线程使用,因此无法释放造成内存泄露。
 

内存泄漏产生的原因在Android中大致分为以下几种:

1.static变量引起的内存泄漏 
因为static变量的生命周期是在类加载时开始 类卸载时结束,也就是说static变量是在程序进程死亡时才释放,如果在static变量中 引用了Activity 那么 这个Activity由于被引用,便会随static变量的生命周期一样,一直无法被释放,造成内存泄漏。

解决办法: 
在Activity被静态变量引用时,使用 getApplicationContext 因为Application生命周期从程序开始到结束,和static变量的一样。

2.线程造成的内存泄漏 
类似于上述例子中的情况,线程执行时间很长,及时Activity跳出还会执行,因为线程或者Runnable是Acticvity内部类,因此握有Activity的实例(因为创建内部类必须依靠外部类),因此造成Activity无法释放。 
AsyncTask 有线程池,问题更严重

解决办法: 
1.合理安排线程执行的时间,控制线程在Activity结束前结束。 
2.将内部类改为静态内部类,并使用弱引用WeakReference来保存Activity实例 因为弱引用 只要GC发现了 就会回收它 ,因此可尽快回收

3.BitMap占用过多内存 
bitmap的解析需要占用内存,但是内存只提供8M的空间给BitMap,如果图片过多,并且没有及时 recycle bitmap 那么就会造成内存溢出。

解决办法: 
及时recycle 压缩图片之后加载图片

4.资源未被及时关闭造成的内存泄漏 
比如一些Cursor 没有及时close 会保存有Activity的引用,导致内存泄漏

解决办法: 
在onDestory方法中及时 close即可

5.Handler的使用造成的内存泄漏 
由于在Handler的使用中,handler会发送message对象到 MessageQueue中 然后 Looper会轮询MessageQueue 然后取出Message执行,但是如果一个Message长时间没被取出执行,那么由于 Message中有 Handler的引用,而 Handler 一般来说也是内部类对象,Message引用 Handler ,Handler引用 Activity 这样 使得 Activity无法回收。

解决办法: 
依旧使用 静态内部类+弱引用的方式 可解决

6.带参数的单例

如果我们在在调用Singleton的getInstance()方法时传入了Activity。那么当instance没有释放时,这个Activity会一直存在。因此造成内存泄露。
解决方法:

可以将new Singleton(context)改为new Singleton(context.getApplicationContext())即可,这样便和传入的Activity没关系了。

Android studio 分析内存泄漏的更多相关文章

  1. 使用 Android Studio 检测内存泄漏与解决内存泄漏问题

    本文在腾讯技术推文上 修改 发布. http://wetest.qq.com/lab/view/63.html?from=ads_test2_qqtips&sessionUserType=BF ...

  2. Android Studio +MAT 分析内存泄漏实战

    对于内存泄漏,在Android中如果不注意的话,还是很容易出现的,尤其是在Activity中,比较容易出现,下面我就说下自己是如何查找内存泄露的. 首先什么是内存泄漏? 内存泄漏就是一些已经不使用的对 ...

  3. 系统剖析Android中的内存泄漏

    [转发]作为Android开发人员,我们或多或少都听说过内存泄漏.那么何为内存泄漏,Android中的内存泄漏又是什么样子的呢,本文将简单概括的进行一些总结. 关于内存泄露的定义,我可以理解成这样 没 ...

  4. 使用新版Android Studio检测内存泄露和性能

    内存泄露,是Android开发者最头疼的事.可能一处小小的内存泄露,都可能是毁于千里之堤的蚁穴.  怎么才能检测内存泄露呢?网上教程非常多,不过很多都是使用Eclipse检测的, 其实1.3版本以后的 ...

  5. 【转】如何使用MAT分析内存泄漏

    原文链接:http://www.lightskystreet.com/2015/09/01/mat_usage/ MAT - Memory Analyzer Tool 使用进阶 Sep 1, 2015 ...

  6. Atitit.提升稳定性-----分析内存泄漏PermGen OOM跟解决之道...java

    Atitit.提升稳定性-----分析内存泄漏PermGen OOM跟解决之道...java 1. 内存区域的划分 1 2. PermGen内存溢出深入分析 1 3. PermGen OOM原因总结 ...

  7. 使用Memory Analyzer tool(MAT)分析内存泄漏(二)

    转载自:http://www.blogjava.net/rosen/archive/2010/06/13/323522.html 前言的前言 写blog就是好,在大前提下可以想说什么写什么,不像投稿那 ...

  8. 使用Memory Analyzer tool(MAT)分析内存泄漏

    前言的前言 写blog就是好,在大前提下可以想说什么写什么,不像投稿那么字字斟酌.上周末回了趟成都办事,所以本文来迟了.K117从达州经由达成线往成都方向走的时候,发现铁路边有条河,尽管我现在也不知道 ...

  9. 使用androidstudio 分析内存泄漏

    分析内存泄漏 http://www.jianshu.com/p/c49f778e7acf

随机推荐

  1. EditPlus远程编辑、语法高亮、编译运行源代码设置

    最近写代码的过程中,除了写Java时用的Eclipse.在Linux下编辑的Vi之外,有时也会用EditPlus打开一些文件,如配置文件.日志文件.脚本等.个人觉得EditPlus在很多场景下比较好用 ...

  2. 谈谈springMVC和Strut2的理解

    关于struts2框架原理 执行流程 struts2框架的核心是一个过滤器,我们编写的action类都继承ActionSupport的接口(顶层是一个过滤器filter),用户发送请求,经过核心过滤器 ...

  3. Linux crontab定时执行任务

    1.设置定时任务的命令是crontab -e首次使用crontab的时候会让你选择编辑工具,看个人喜好了.选择一个即可.如果以后想换默认编辑工具,可以按照下面的提示运行命令"select-e ...

  4. Unknown column 'a.root_id' in 'where clause'解决方法

    最近遇到一个问题, update  sy_user as a inner join sy_user_charge_log as b on b.username=a.username set recon ...

  5. SHOPNC占用CPU过高

    今天一个SHOPNC商城突然变慢,查看服务器情况,发现MYSQL占用181%CPU,然后查看PHP慢查询,发现这样的内容 [22-Nov-2016 20:55:41] [pool www] pid 5 ...

  6. TCP数据包的封包和拆包

    //该段博文为引用,非原创. 封包和拆包 作者:fengge8ylf  博客:http://blog.csdn.net/fengge8ylf 对于基于TCP开发的通讯程序,有个很重要的问题需要解决,就 ...

  7. Struts框架——(二)Struts原理with登录实例

    二. Struts基本工作流程 假设现在有以下情景: 用户正在浏览一个用STRUTS的技术构建的网站主页,主页上有个登陆表单,用户填好登陆名和密码,单击"登陆"按钮,就激活了以下一 ...

  8. laravel(三):larave基本使用

    1.基本视图显示 前文已经介绍如何创建控制器.动作和视图,下面我们来创建一些更实质的功能. 在此之前我们需要修改一些配置: app/config/app.php 文件中的 debug 选项设置为 tr ...

  9. Android 获取当前时间问题1

    获取的写法如下: Calendar c = Calendar.getInstance();//可以对每个时间域单独修改 int year = c.get(Calendar.YEAR); int mon ...

  10. 阅读笔记Multi-task Learning for Stock Selection [NIPS1996]

    Multi-task Learning for Stock Selection  Joumana Ghosn and Yoshua Bengio 摘要 用人工神经网络预测未来回报以便于做出对应的金融决 ...