很多其它内容,可訪问个人博客www.liangfeizc.com

错误代码

假设在Activiy中通过内部类(Runnable)的方式定义了一个变量runnable,

final Runnable runnable = new Runnable() {
public void run() {
// ... do some work
}
};
handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(10)

由于Runnable不是static类型,所以会有一个包括Activity实例的implicit reference --- Activity.this。

假设Activity在runnable变量run之前(10s内)被finish掉了可是Activity.this仍然存在。那么Activity的对象就不会被GC回收,从而导致memory leak

即使使用一个静态内部类,也不能保证万事大吉。

static class MyRunnable implements Runnable {
private View view;
public MyRunnable(View view) {
this.view = view;
}
public void run() {
// ... do something with the view
}
}

如果在runnable运行之前。View被移除了。可是成员变量view还在继续引用它,仍然会导致memory leak

上面的两个样例其中,导致内存泄露的两种使用方法各自是隐式引用(implicit reference)显式引用(explicit reference)

解决方法

解决隐式引用的方法比較简单。仅仅要使用内部非静态类(non-static inner class)或者 top-level class(在一个独立的java文件里定义的变量)就能够将隐式变为显式,从而避免内存泄露。

假设继续使用非静态内部类,那么就要在onPause的时候手动结束那些挂起的任务(pending task)。

关于怎样结束不论什么,Handler可參考这篇文章中的Canceling a pending RunnableCanceling pending Messages。HandlerThread可參考这篇文章

解决第二个问题要用到WeakReference。WeakReference的使用方法能够google一下。简而言之就是:仅仅要还有其它的stronger reference。WeakReference就能够继续引用。

static class MyRunnable implements Runnable {
private WeakReference>View< view;
public MyRunnable(View view) {
this.view = new WeakReference>View<(view);
}
public void run() {
View v = view.get();
if (v != null) {
// ... do something with the view
}
}
}

这样一来问题就攻克了。美中不足的是每次使用view之前都要做空指针推断。另外一个比較高效的方法就是在onResume中为runnable的view赋值,在onPause中赋值为null。

private static class MyHandler extends Handler {
private TextView view;
public void attach(TextView view) {
this.view = view;
}
public void detach() {
view = null;
}
@Override
public void handleMessage(Message msg) {
// ....
}

总结

在继承Handler或者HandlerThread的时候。

  • 尽量定义一个static类或者top-level类。
  • 假设用到了ui元素,一定要在Activity的生命周期接触之前释放掉。

參考

Asynchronous Android - Steve Liles

Android -&gt; 怎样避免Handler引起内存泄露的更多相关文章

  1. Android中使用Handler造成内存泄露的分析和解决

    什么是内存泄露?Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向 ...

  2. Android中使用Handler造成内存泄露

    1.什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用 ...

  3. Android Handler的内存泄露问题+解决方案

    谈谈handler的内存泄露问题 再来看看我们的新建Handler的代码: private Handler mHandler = new Handler() { @Override public vo ...

  4. Android使用Handler造成内存泄露的分析及解决方法

    一.什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用 ...

  5. Android学习系列(37)--App调试内存泄露之Context篇(下)

    接着<Android学习系列(36)--App调试内存泄露之Context篇(上)>继续分析. 5. AsyncTask对象 我N年前去盛大面过一次试,当时面试官极力推荐我使用AsyncT ...

  6. Android中的内部类引起的内存泄露

    引子 什么是内部类?什么是内存泄露?为什么Android的内部类容易引起内存泄露?如何解决? 什么是内部类? 什么是内部类?什么又是外部类.匿名类.局部类.顶层类.嵌套类?大家可以参考我这篇文章 ,再 ...

  7. Android学习系列(36)--App调试内存泄露之Context篇(上)

    Context作为最基本的上下文,承载着Activity,Service等最基本组件.当有对象引用到Activity,并不能被回收释放,必将造成大范围的对象无法被回收释放,进而造成内存泄漏. 下面针对 ...

  8. Android Studio 使用Memory Monitor进行内存泄露分析

    在使用Android Studio进行内存泄露分析之前,我们先回顾一下Java相关的内存管理机制,然后再讲述一下内存分析工具如何使用. 一.Java内存管理机制 1. Java内存分配策略 Java ...

  9. Handler导致内存泄露分析

    (非静态)内部类引起内存泄漏的原因         内部类的实现其实是通过编译器的语法糖(Syntactic sugar)实现的,通过生成相应的子类即以OutClassName$InteriorCla ...

随机推荐

  1. uvc摄像头代码解析7

    13.uvc视频初始化 13.1 uvc数据流控制 struct uvc_streaming_control { __u16 bmHint; __u8 bFormatIndex; //视频格式索引 _ ...

  2. lucene做简单的文件索引

    package com.mylucene; import java.io.File; import java.io.FileReader; import java.io.IOException; im ...

  3. Servlet的学习之Request请求对象(2)

    在上一篇<Servlet的学习(十)>中介绍了HttpServletRequest请求对象的一些常用方法,而从这篇起开始介绍和学习HttpServletRequest的常用功能. 使用Ht ...

  4. Tomcat详细用法学习(四)

    本篇接上一篇<Tomcat详细用法学习(三)>,主要讲解配置虚拟主机.打包web应用成war包和Tomcat的体系结构 对于Tomcat服务器,可以放置多个网站(多个web应用),这就是讲 ...

  5. [IOS]Setting Bundle + StoryBoard

    用storyboard添加一个导航栏,其中首页有一个switch,与setting联动,还有一个button,使用modal连接另一个viewControl,其上也有一个按钮,按下销毁本viewCon ...

  6. hdu 4507 数位dp(求和,求平方和)

    http://acm.hdu.edu.cn/showproblem.php?pid=4507 Problem Description 单身! 依旧单身! 吉哥依旧单身! DS级码农吉哥依旧单身! 所以 ...

  7. tc3162目录

    lsbin      dev      lib      proc     tmp      usrboaroot  etc      linuxrc  sbin     userfs   var# ...

  8. [置顶] 自己动手写Web容器之TomJetty之六:动态页面引入

    传送门 ☞ 1.Web服务内功经脉 传送门 ☞ 2.让服务动起来 传送门 ☞ 3.掀起请求盖头来 传送门 ☞ 4.静态页面起步 传送门 ☞ 5.包装请求参数 在上一节,我们已经完成了TomJetty服 ...

  9. c#indexof使用方法

    IndexOf() 查找字串中指定字符或字串首次出现的位置,返首索引值,如: str1.IndexOf("字"): //查找"字"在str1中的索引值(位置) ...

  10. 在VC++中启用内存泄露检测

    检测内存泄漏的主要工具是调试器和 CRT 调试堆函数.若要启用调试堆函数,请在程序中包括以下语句: #define CRTDBG_MAP_ALLOC#include <stdlib.h># ...