一个印象深刻的Bug修复之安卓APP内存泄露-阿里云开发者社区

开发者社区> 游客t7timf3egkek2> 正文

一个印象深刻的Bug修复之安卓APP内存泄露

简介: 以前,在做Java程序员时候,兼职写公司的APP程序,当时没有太多的开发经验,出现了Handler 使用不当形成的内存泄漏。这个事情让我影响非常的深刻。废话不多说,我们直接看看当时的情况。部分代码已脱敏。
+关注继续查看

以前,在做Java程序员时候,兼职写公司的APP程序,当时没有太多的开发经验,出现了Handler 使用不当形成的内存泄漏。这个事情让我影响非常的深刻。废话不多说,我们直接看看当时的情况。部分代码已脱敏。

public class MainActivity extends AppCompatActivity {

 

    private Handler handler = new Handler() {

        @Override

        public void handleMessage(Message msg) {

            // ...

        }

    };

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        // ...

    }

}

 

这是当时Handler的使用。我来介绍下当时的情况,当使用内部类(包括匿名类)来建立Handler的时候,Handler对象会隐式地持有一个外部类对象的引用

而Handler一般会伴随着一个耗时的后台线程(例如从网络拉取图片)一块儿出现,这个后台线程在任务执行完毕(例如图片下载完毕)以后,经过消息机制通知Handler,而后Handler把图片更新到界面。然而,若是用户在网络请求过程当中关闭了Activity,正常状况下,Activity再也不被使用,它就有可能在GC检查时被回收掉,但因为这时线程还没有执行完,而该线程持有Handler的引用(否则它怎么发消息给Handler?),这个Handler又持有Activity的引用,就致使该Activity没法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,若是你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达以前,会有一条MessageQueue -> Message -> Handler -> Activity的链,致使你的Activity被持有引用而没法被回收。

当时就是不理解这些基本原理,所以排查了好几天。想哭的心都有了。现在给各位同学建议,这种基本概念我们一定要熟练掌握,通常 java 中所说的内存泄漏指的是 java 堆中所产生的内存泄漏,java 堆中内存是由 java 虚拟机的“GC”所管理的,java 虚拟机实时监控到一些对象不可到达,即在之后的程序中不会被用到,触发 GC 时,这样的对象将会被回收掉,其所占的内存也将释放。从对象的生命周期角度来说,若是一个长生命周期的对象持有了一个短生命周期对象的引用,将致使这个短生命周期的对象没法回收,其所占的内存释放不了,就会有内存泄漏的风险。

 

如果我们在实际开发中出现这种情况,该如何检测呢。我在这里给同学们推荐两个常用方法。

 

1. 使用 Android Profiler 检测

使用内存分析器来执行如下操做:

在可能致使性能问题的时间轴中寻找不良的内存分配模式,我使用这个工具相信分析结果很明确了。上面示例比较简单,针对复杂的问题,咱们还可使用 eclipse-MAT 工具加以分析。

 

2. 利用软引用和弱引用解决OOM问题

根据前面讲了关于软引用和弱引用相关的基础知识,那么到底如何利用它们来优化程序性能,从而避免OOM的问题呢?

下面举个例子,假若有一个应用须要读取大量的本地图片,若是每次读取图片都从硬盘读取,则会严重影响性能,可是若是所有加载到内存当中,又有可能形成内存溢出,此时使用软引用能够解决这个问题。

设计思路是:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。在Android开发中对于大量图片下载会常常用到。

 

针对上述例子,首先咱们把匿名内部类 Handler 声明为静态内部类,这样Handler类中就不持有 Activity 的引用了。可是,这样在 Handler 中要使用 activity 对象,则经过弱引用来解决这个问题。

 

public class MainActivity extends AppCompatActivity {

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        // ...

    }

 

    private static class NoLeakHandler extends Handler {

        

        //持有弱引用MainActivity,GC回收时会被回收掉.

        private WeakReference<MainActivity> mActivity;

 

        public NoLeakHandler(MainActivity activity) {

            mActivity = new WeakReference<>(activity);

        }

 

        @Override

        public void handleMessage(Message msg) {

            super.handleMessage(msg);

        }

    }

}

 

固然针对 Handler 的内存泄漏,咱们也能够经过程序来解决:

在关闭Activity的时候停掉你的后台线程。线程停掉了,就至关于切断了Handler和外部链接的线,Activity天然会在合适的时候被回收。

若是你的Handler是被delay的Message持有了引用,那么使用相应的Handler方法:removeCallbacks(Runnable r)和removeMessages(int what),在页面销毁时把消息对象从消息队列移除就好了。

 

@Override

public void onDestroy() {

   // 移除全部消息

   handler.removeCallbacksAndMessages(null);

   // 或者移除单条消息

   handler.removeMessages(what);

}

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
仿酷狗音乐播放器开发日志二十五 duilib右键事件的不足的bug修复
转载请说明原出处,谢谢~~        虽然仿酷狗的各个菜单早就写好了,但是一直没有附加到程序里。今天把菜单和播放列表控件关联时发现了问题。        和播放列表相关的菜单有三个,分别是每个音乐项目控件相关的菜单、分组的菜单、音乐电台的菜单。
916 0
duilib CDateTimeUI 在Xp下的bug修复
转自:http://my.oschina.net/u/343244/blog/370131 CDateTimeUI 的bug修复。
857 0
Expert 诊断优化系列------------------内存不够用么?
现在很多用户被数据库的慢的问题所困扰,又苦于花钱请一个专业的DBA成本太高。软件维护人员对数据库的了解又不是那么深入,所以导致问题迟迟不能解决,或只能暂时解决不能得到根治。开发人员解决数据问题基本又是搜遍百度各种方法尝试个遍,可能错过诊断问题的最佳时机又可能尝试一堆方法最后无奈放弃。
903 0
【Redis】线上7000w+ keys && 16G内存100%的排查修复经历
起因 我们使用的一直是阿里云的redis, 我们并非高并发应用, 主要也就是拿来做分布式锁和少量的缓存, 基本不怎么需要维护, 昨天下午突然收到一封告警邮件, 线上redis内存使用100%, 瞬间神经绷紧感觉上控台确认.
3582 0
duilib List控件,横向滚动时列表项不移动或者移动错位的bug的修复
转载请说明出处,谢谢~~       这篇博客已经作废,只是留作记录,新的bug修复博客地址:http://blog.csdn.net/zhuhongshu/article/details/42264673       之前就在群里挺群友朋友说道,使用List控件,里面加入ListContainElementUI元素,当List出现横向滚动条时,滚动条滑动后元素不跟着滑动或者滑动后位置不正确。
975 0
duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复
转载请说明出处,谢谢~~       群里有朋友提到了使用Combo控件时,当下拉列表出现,此时鼠标滚轮滚动,下拉列表就自动消失了。我看了一下源码,这个bug的修复很简单。
1153 0
fastjson 1.2.76版本发布,BUG修复增强兼容
fastjson是一个bug fixed的版本,大家按需升级
136 0
duilib relativepos属性导致控件错误的bug修复
转载请说明出处,谢谢~~         我在仿酷狗音乐播放器的开发日志系列里,曾经提到了这个bug,文章地址为:http://blog.csdn.net/zhuhongshu/article/details/38145365。
933 0
duilib 修复Text控件无法设置宽度的bug,增加自动加算宽度的属性
转载请说明原出处,谢谢~~:       今天有朋友反映CTextUI控件无法设置宽度,于是修复了这个bug,顺便给Text控件增加了一个自动计算宽度的属性,描述如下       bug出现在EstimeteSize函数,...
925 0
9
文章
67
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载