`
ericbaner
  • 浏览: 173784 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android内存泄露之Context引用

 
阅读更多

以下是对Android SDK 一篇文章的简单翻译,原文地址为:

http://developer.android.com/resources/articles/avoiding-memory-leaks.html

 

Andriod应用程序是运行在linux上的dalvik虚拟机,其可分配的堆内存有一个限制,如T-moblie G1为16MB。对手机来说,16MB算是很多了,但对一些开发者来说是太少了。因此,尽管你可能不打算用光这些内存,你也应该尽量用最少的内存,以让其它应用程序不因为系统内存过低而被系统给强制杀掉。在Android里,越多的应用可以在内存里保持,对用户来说,就可以更快地在各个应用之间切换。

 

Android应用里一个最常见的内存泄露例子是: 保持对一个Context对象的长引用(Keeping a long-lived reference to a Context)。

 

在Android里,一个Context对象可以用来做很多操作,但最常见的是用来载入和访问资源。这也是所有Widget对象都要在其构造函数里接收一个Context参数的原因。在一个常规Android应用里,通常有两种Context, 即 Activity 和 Application。通常,开发者会传Activity对象到需要Context的类和方法。

 

@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);
  
  TextView label = new TextView(this);
  label.setText("Leaks are bad");
  
  setContentView(label);
}

 

这意味着views有一个指向整个activity的引用,同时可以引用到activity所持有的任何资源,比如整个view层次结构和它所有的资源。因此,如果泄露了Context对象(泄露指持有一个指向Context对象的引用而阻止内存垃圾回收器GC来回收它),将会泄露很多内存。 如果不小心的话,泄露整个activity对象真是很容易的事。

 

当屏幕横竖方向切换时,系统默认会摧毁当前activity,然后创建一个新的activity,当然之前的activity状态会保存。在这个过程中,Android会重新载入应用UI资源。 因此,假如你写了一个应用,显示一个很大的bitmap图像,你不想在每次屏幕横竖方向切换时都重新载入图像一次,最容易的方式是将图像存在一个静态成员里:

 

private static Drawable sBackground;
  
@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);
  
  TextView label = new TextView(this);
  label.setText("Leaks are bad");
  
  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);
  
  setContentView(label);
}
 

以上代码确实运行很快,但是非常错误的,其泄露了在第一次屏幕方向切换前创建的activiy对象。当一个Drawable对象连接到一个view时,view会被设置为Drawable对象的callback。对以上代码,drawable对象将有一个指向TextView的引用,而TextView自身有一个指向activity(Context)的引用,而activity将引用到非常多的其它资源(取决于你的代码实现)。

 

此示例是一种最简单的泄露Context对象的案例。 你可以在 Home screen's source code (查找unbindDrawables方法)看到我们是如何规避此问题的。

即:当activity被摧毁时,设置保存的drawable对象的callback为null。

有意思的是,有一些情况你可能会创建一系列的Context泄露,这是相当糟糕的,会使你很快地用光内存。

 

如何避免呢? 有两种简单的方式来避免Context相关的内存泄露。最明显的一种是避免将Context对象传出其自身的作用域。上面的示例显示了静态引用的方式,其实内部类及其隐式地引用外部类也是同样危险的。第二种方式是使用Application context对象。 Application context将会一直存在,只要应用程序在存活状态,且不依赖于activity的生命周期。 如果你打算保持一个需要context的长期存活的对象,那就使用application对象。其可以很容易地通过 Context.getApplicationContext() or Activity.getApplication() 得到。

 

总之, 要避免Context相关的内存泄露,牢记以下几点:

 

1. 不要保存一个指向activity context的长期存活的引用(指向一个acitivy的引用应该和该activity拥有同样的生命周期)。

 

2.  使用application context对象来代替acitivity context对象。

 

3.  如果不能控制activity里的非静态内部类的生命周期的话,避免使用之。 尽量使用静态内部类,在其内部持有指向activity的弱引用(weak reference)。如ViewRoot及其W内部类示例。

 

4. 垃圾内存回收器并不能保证防止内存泄露。

 

 

 

 

 

分享到:
评论

相关推荐

    Android webview 内存泄露的解决方法

    Android webview 内存泄露的解决方法 最近在activity嵌套webview显示大量图文发现APP内存一直在涨,没法释放内存,查了很多资料,大概是webview的一个BUG,引用了activity导致内存泄漏,所以就尝试传递...

    详解Android内存泄漏检测与MAT使用

    内存泄漏主要原因就是一个生命周期长的对象,持有了一个生命周期短的对象的引用。这样,会导致短的对象在该回收时候无法被回收。Android中比较典型的有:1、静态变量持有Activity的context。2、或者Handler持有某个...

    Android内存泄漏终极解决篇(下)

    在 Android内存泄漏终极解决篇(上)中我们介绍了如何检查一个App是否存在内存泄漏的问题,本篇将总结典型的内存泄漏的代码,并给出对应的解决方案。内存泄漏的主要问题可以分为以下几种类型: 静态变量引起的内存...

    android中用getApplicationContext()会不会避免某些内存泄漏问题?

    RT,在android开发中,如果在使用context的地方全部用getApplicationContext()会不会避免某些内存泄漏问题? 首先,Activity的Context和Application的Context肯定不是一个东西,一个是当前活动的 Context,它的生命...

    5个Android开发中比较常见的内存泄漏问题及解决办法

    android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了。 内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统分配的内存...

    Android编程中避免内存泄露的方法总结

    作为我的一项工作,我仔细研究了Android应用的内存泄露问题,大多数情况下它们是由同一个错误引起的,那就是对一个上下文(Context)保持了长时间的引用。 在Android中,上下文(Context)被用作很多操作中,但是大...

    Android性能优化之利用强大的LeakCanary检测内存泄漏及解决办法

    最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来。所以决定抽空学习总结...

    Android常见的几种内存泄漏小结

    在Android程序开发中,当一个对象已经不需要再使用了,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中,内存泄漏就产生了。内存...

    Android中的内存泄漏

    什么是内存泄漏 长生命周期的对象持有了短生命周期的对象,从而导致短生命周期的对象不能被释放 垃圾回收机制 垃圾回收机制分为:引用计数法、可达性分析法 引用计数法(有循环引用的问题):Python、Object-C、Swift ...

    android自定义短信倒计时view

    为了保证activity销毁的同时倒计时线程依然进行同时重新创建销毁又不会导致内存泄漏,我使用了handler的弱引用将handler和runnable设置成静态,同时通过一系列变量来销毁关闭线程保存状态,话不多说先看效果图: ...

    Android自定义短信倒计时view流程分析

    为了保证activity销毁的同时倒计时线程依然进行同时重新创建销毁又不会导致内存泄漏,我使用了handler的弱引用将handler和runnable设置成静态,同时通过一系列变量来销毁关闭线程保存状态,话不多说先看效果图: ...

    Android蓝牙通信框架BluetoothKit.zip

    四、屏蔽了接口异步回调可能持有调用端Activity引用导致的内存泄露 五、利用动态代理自动将所有操作封闭在工作线程,所以整个框架无锁 使用 // 首先,需要按如下方式初始化BluetoothClient: ...

Global site tag (gtag.js) - Google Analytics