文档章节

Android内存泄漏分析实战

拉偶有所依
 拉偶有所依
发布于 2015/06/26 10:17
字数 1518
阅读 7956
收藏 17
点赞 0
评论 1

内存泄漏简介

java可以保证当没有引用指向对象的时候,对象会被垃圾回收器回收,与c语言自己申请的内存自己释放相比,java程序员轻松了很多,但是并不代表java程序员不用担心内存泄漏。当java程序发生内存泄漏的时候往往具有隐蔽性。因此要借助一些专业的平台资源去保证安全性,例如可以通过加密实现

定义

引用百度百科的定义:“用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束”。从程序猿的角度来看“内存泄漏”,其实就是一个对象的生命周期超出了程序员所预期的长度(就叫它“该死不死”吧!),那么这个对象就泄漏了。

android开发中的内存泄漏

android应用程序本身系统分配的内存很少,一旦发生泄漏,程序很快就会变得非常卡顿,直至OOM崩溃。接下来将通过一个案例(只是为了分析内存泄漏而设计的玩具程序,切勿模仿)来介绍内存泄漏分析工具MAT,以及内存分析的技巧。

公欲善其事,先利其器

准备内存泄漏的分析工具,可以安装eclipse插件mat。如果eclise安装mat不成功,那可能是缺少必要的libs,如果嫌找库麻烦,可以只勾选第二项安装,不过会缺少某些功能,但是也够用了。 
在线安装:
http://download.eclipse.org/mat/1.4/update-site/ 
下载安装:
http://mirror.hust.edu.cn/eclipse//mat/1.4/MemoryAnalyzer-1.4.0.201406041413.zip

mat插件如何使用

如果已经成功安装好了mat工具,使用起来非常简单,首先将需要分析的应用程序跑起来,打开eclipse的devices视图你将会看到点击“Dump Hprof file”按钮,注意点击一下就可以了,然后等待(等待几秒)dump一个内存快照出来,接下来就会自动打开mat的视图了,如果mat没有安装成功,会让你保存一个.hprof文件到本地。看看下面的图例吧

dump hprof启动mat工具

人为制造一个内存泄漏

自定义一个ActivityManager,提供两个方法,分别用来注册与反注册Activity。源码下载

public class ActivityManager {
   private List<Activity> mActivities = new ArrayList<>();
   private static ActivityManager sInstance;

   private ActivityManager() {
   };

   public static ActivityManager instance() {
       if (sInstance == null) {
           sInstance = new ActivityManager();
       }

       return sInstance;
   }

   public void registActivity(Activity activity) {
       mActivities.add(activity);
   }

   public void unRigistActivity(Activity activity) {
       mActivities.remove(activity);
   }
}

在MainActivity的onCreate与onDestroy中分别调用registActivity和registActivity方法进行注册与反注册。但是OtherActivity却只是注册了,而忘记了反注册。

public class MainActivity extends Activity {
   public static final String TAG = MainActivity.class.getSimpleName();

   private Button mBtn;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       mBtn = (Button) findViewById(R.id.btn);
       mBtn.setOnClickListener(new OnClickListener() {

           @Override
           public void onClick(View v) {
               Intent intent = new Intent();
               intent.setClass(MainActivity.this, OtherActivity.class);
               startActivity(intent);
           }
       });
       
       ActivityManager.instance().registActivity(this);
   }

   @Override
   protected void onDestroy() {
       super.onDestroy();
       
       ActivityManager.instance().registActivity(this);
   }

public class OtherActivity extends Activity {
   public static final String TAG = OtherActivity.class.getSimpleName();

   private Object[] mObjs = new Object[10000];//模拟快速消耗内存,使效果明显
   private Button mBtn;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_other);
       mBtn = (Button) findViewById(R.id.btn);
       mBtn.setOnClickListener(new OnClickListener() {

           @Override
           public void onClick(View v) {
               for (int i = 0; i < mObjs.length; i++) {
                   mObjs[i] = new Object();
               }
               
               finish();
           }
       });

       ActivityManager.instance().registActivity(this);
   }

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

案例中的内存泄漏是人为构造的,所以我们事先已经知道有泄漏了,但是实际的开发过程中,内存泄漏是隐蔽的,一开始我们并不知道,所以我们需要通过一些手段来测试APP是否有内存泄漏。首先在Devices视图中选中需要测试的进程,然后点击Device视图面板的Update Heap按钮,然后打开Heap视图,点击Cause GC。然后反复的在MainActivyt和OtherActivity之间切换。观察Heap size的变化。你会发现内存一直在增加。没有稳定下来的趋势。这个时候你就有理由怀疑内存泄漏了。

Update heap观察heap size等变化情况

找出泄漏的对象

按照前面mat的使用步骤,dump一个内存快照出来,然后从分析报告中点击“Leak suspects”这里会列车可能泄漏的对象,其中你会发现“ com.vjson.leaks.OtherActivity”的身影。OtherActivity这个类有33个实例,作为代码的生产者,你应该一下子就会发现,原来是OtherActivity泄漏了。发现它泄漏之后,如何找出是哪一个对象持有了OtherActivity对象的引用呢?

可能泄漏的报告

找出引用链

使用OQL对象查询语言查询出泄漏的对象,写过SQL的同学一定对她有一种既陌生又熟悉的感觉,和SQL非常相似,语法简单易懂,但是非常强大select *from com.vjson.leaks.OtherActivity赛选出OtherActivity这一类对象,然后选择“exclude weak/soft references”赛选出除了软引用和弱引用之外的对象,也就是强引用了!。对象的引用类型不在本文的讲解范围,但是你一定要知道“强引用”,“软引用”,“弱引用”。“幽灵引用”,如果不知道自行脑补去吧!

OQL对象查询找出引用链

对象引用链

然后找出GC的根节点,从图二种可以看出,原来Activity对象被ActivityManager里面的ArrayList给hold住了,所以接下来的工作就是在OtherActivity的onDestroy中反注册,内存泄漏就被解决了。

Android开发中常见的内存泄漏

对象没有反注册

数据库cursor没有关闭

Bitmap没有回收

ListView item没有复用

Handler在Activity中定义为非static的匿名内部类

总结

如果耐心的看完本文,那么恭喜你妈妈再也不用担心内存泄漏了。其实只要掌握了分析问题的技巧与工具,内存泄漏so easy。文章中只是简单的介绍了工具与技巧,这其中还有很多技巧需要自己去摸索。 


© 著作权归作者所有

共有 人打赏支持
拉偶有所依
粉丝 26
博文 81
码字总数 138944
作品 0
长沙
加载中

评论(1)

黑色的月牙
强烈谴责"爱加密"剽窃我的文章,http://vjson.com/wordpress/android%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F%E5%88%86%E6%9E%90%E5%AE%9E%E6%88%98.html
Android内存优化(六)LeakCanary使用详解

相关文章 Android性能优化系列 Java虚拟机系列 1.概述 如果使用MAT来分析内存问题,会有一些难度,并且效率也不是很高,对于一个内存泄漏问题,可能要进行多次排查和对比。 为了能够简单迅速...

刘望舒
2017/09/10
0
0
Android应用内存泄漏的定位、分析与解决策略

Hello,大家好,我是Clock。翻了一下简书,发现有一个多月没有更新博客,本来今天打算和妹纸去电影院看《你的名字》,然后再去到处浪的。 结果因为妹纸公司临时有事,她不得不回公司一趟......

D_clock爱吃葱花
06/29
0
0
一步步拆解 LeakCanary

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 java 源码系列 - 带你读懂 Reference 和 ReferenceQueue https://blog.csdn.net/gdutxiaoxu/article/details/80738581 一步步拆解 ...

xujun9411
07/04
0
0
[Android]App 内存泄漏检查工具MAT

Android App发生内存泄漏,常见的有Bitmap 使用后沒有recycle(),Drawable 使用后沒有setCallback(null)等。 Eclipse 有个插件工具MAT(Memory Analyzer Tool)可以帮助定位内存泄漏的对象。 ...

清水湾2012
2013/08/01
0
1
【android测试】值得学习的android测试知识连接

Android应用程序的debug属性: http://blog.csdn.net/hudashi/article/details/8698142 彻底解决Android 应用方法数不能超过65535的问题 http://blog.csdn.net/yuanzeyao/article/details/418......

beijing_zbs
2014/12/02
0
0
历时四年,给Google提交的Android Framework Bug终于被Fixed了

2014年在做一个Android终端设备开发过程中,发现了一个Android Framework层的Bug,给Google提交了issue和解决方案,和外界传言一致Google一般不太在意个人开发者提交的issue,直到2017年12月...

image_c
07/12
0
0
100%移植阿里云移动测试技术_竟仅需1周?!——移动测试专有云(3)——内容详解

一、自动化测试服务 Android兼容性测试 Android兼容性测试旨在帮助解决Android应用在不同真机机型上的各类兼容性问题,包括 Crash/ANR分析、6项性能分析、UI检测、3个版本的覆盖安装检测等。...

乐乎无趣
2017/11/02
0
0
0-2岁的app开发人员必读,Android开发APP前的准备事项

随着移动互联网的兴起,各行各业对移动应用的需求越来越大,从事APP开发的人也越来越多,APP开发行业可以说是方兴未艾。APP开发是比较复杂的事情,涉及产品、美工设计、服务器端开发、Andro...

传授知识的天使
06/06
0
0
腾讯技术分享:Android版手机QQ的缓存监控与优化实践

本文内容整理自公众号腾讯Bugly,感谢原作者的分享。 1、问题背景 对于Android应用来说,内存向来是比较重要的性能指标。内存占用过高,会影响应用的流畅度,甚至引发OOM,非常影响用户体验。...

JackJiang2011
04/08
0
0
内存泄露和LeakCanary的故事

新鲜文章请关注微信公众号: JueCode 今天我们来聊一聊Android中的内存泄露和内存泄露的检测工具LeakCanary。Java有垃圾回收线程为什么还会发生内存泄露?原因就是外部人为持有对象引用,持有...

juexingzhe
05/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

看看 LinkedList Java 9

终于迎来了 LinkedList 类,实现的接口就有点多了 Serializable, Cloneable, Iterable<E>, Collection<E>, Deque<E>, List<E>, Queue<E>。LinkedList是一个实现了List接口和Deque接口的双端链......

woshixin
15分钟前
0
0
算法 - 冒泡排序 C++

大家好,我是ChungZH。今天我给大家讲一下最基础的排序算法:冒泡排序(BubbleSort)。 冒泡排序算法的原理如下: 比较相邻的元素。如果第一个比第二个大(可以相反),就交换他们两个。 对每...

ChungZH
17分钟前
0
0
jquery ajax request payload和fromData请求方式

请求头的不同 fromData var data = { name : 'yiifaa'};// 提交数据$.ajax('app/', { method:'POST', // 将数据编码为表单模式 contentType:'application/x-ww...

lsy999
20分钟前
0
0
阿里P7架构师,带你点亮程序员蜕变之路

前言: Java是现阶段中国互联网公司中,覆盖度最广的研发语言。 掌握了Java技术体系,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能有立足之地。 有不少朋友问,成为Java架...

Java大蜗牛
21分钟前
1
0
Ecstore 在没有后台管理界面(维护)的情况如何更新表的字段

window 系统: 切换到:app\base 目录下: C:\Users\qimh>d: D:\>cd D:\WWW\huaqh\app\base 执行:D:\WWW\huaqh\app\base>cmd update linux 系统: 1># cd /alidata/www.novoeshop.com/app/......

qimh
26分钟前
0
0
设计模式-策略模式

策略模式 解释 对工厂模式的再次封装,使用参数控制上下文信息(将工厂返回的实例赋值给context field) 不会返回bean实例,只是设置对应的条件 调用context的方法(调用field的方法) 用户只...

郭里奥
29分钟前
0
0
python使用有序字典

python自带的collections包中有很多有用的数据结构可供使用,其中有个叫OrderedDict类,它可以在使用的时候记录元素插入顺序,在遍历使用的时候就可以按照原顺序遍历。 a = {"a":1,"b"...

芝麻糖人
58分钟前
0
0
RestTemplate HttpMessageConverter

RestTemplate 微信接口 text/plain HttpMessageConverter

微小宝
59分钟前
0
0
mysql视图/存储过程/函数/事件/触发器

--语法参考:https://dev.mysql.com/doc/ (当前用的是5.6) https://dev.mysql.com/doc/refman/5.6/en/sql-syntax-data-manipulation.html --视图 CREATE VIEW test.v AS SELECT * FROM t;......

坦途abc
今天
0
0
MySQL参数优化案例

环境介绍 硬件配置 cpu核心数 内存大小 磁盘空间 16核 256G 3T 软件环境 操作系统版本 mysql版本 表数目 单表行数 centos-7.4 mysql-5.7.22 128张表 2kw行 优化层级与指导思想 优化层级 MySQ...

小致dad
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部