【Android外文翻译 - 01】避免内存泄漏

原文地址:http://developer.android.com/resources/articles/avoiding-memory-leaks.html

——转载请注明出处,谢谢。

Android应用至少是运行在内存限制为16MB的G1手机上。这些内存对手机来说已经足够了,但对某些开发者来说还远远不够。尽管不打算耗尽这些内存,但应该尽可能少地使用内存,以免把其他运行中的程序杀死(由于内存不足)。对用户来说,内存中保留的程序越多,在应用之间切换的速度就越快。在工作中,我遇到过很多的Android应用中都存在内存泄漏,这些问题大多数都是出自于相同的原因:保持一个对Context(上下文)的长期引用。

在Android平台上,一个Context(上下文)能够被用来做很多事,但最常用的还是加载资源。这就是为什么所有的Widget(控件,例如 TextView、EditText等),在它们的构造函数中都要接收一个Context参数。在一个Android应用中,通常能使用两种 Context,即Activity和Application。一般来说,当开发人员需要一个Context时,使用的是Activity(活动)。

这就意味着,这些View控件对整个Ativity有一个引用,随之,也就对Activity中的所有事物都有了引用;通常引用的事物是整个视图层级结构以及它所有的资源。因此,如果你leak了Context(“leak”的意思是,你对Context有一个引用,那么这就阻止垃圾回收器将它回收),那么,你就泄漏了许多的内存。如果你不当心一些的话,泄漏整个Activiy是相当容易发生的。

当屏幕的方向发生改变的时候,系统将默认地摧毁当前的Activity,并创建一个新的Activity,在这个摧毁与创建的过程中,同时保存了它的状态。如果这么做,Android将重新加载应用的所有UI资源。现在想象一下,你在写一个应用,你需要使用一个Btimap,但你不想在每次屏幕旋转的时候都要重新加载一遍。那么,最简单的方法就是把它保存在一个静态域中:

这段代码运行起来相当快,但是也错的离谱。程序把屏幕第一次旋转时创建的Activity给泄漏了。当Drawable对象被加载到一个View上以后,这个View对象就被设置成为Drawable对象的一个callbak(回调)。在上面的代码片段中,这个Drawable对象对TextView有一个引用,而这个TextView对这个Activity也有一个引用,可怕的是,这个Activiy对很多东西都有引用(这取决于你的代码)。

这是一个最简单的内存泄漏的例子,可以在HomeScreen源码中,看一看我们是如何解决这个问题的( 查找unbindDrawables() 方法) ,这就是当activity 被销毁的时候将drawables的回调设为null 。有趣的是,你可能创造出一系列context泄漏的情况有很多,这非常糟糕。它们将很快导致内存溢出。

有两种简单的方法来避免Context相关的内存泄漏。最显著地一个是避免Context 溢出它自己的范围之外。上面的例子展示的是使用静态引用的情况,然而,内部类以及它们对其外部类的的隐式引用也是同样危险的。第二种解决方法是使用 Application context。这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity 的生存周期。如果你想保持一个需要context的长期对象,记得使用application 对象。你可以通过调Context.getApplicationContext()或Activity.getApplication()来获取应用对象。

总而言之,想要避免与context 相关的内存泄漏,记住以下几点:

1.要保持对activity-context的长期引用( activity引用的生存周期应该和activity自身的生命周期相同)。

2.试着使用application-context替代activity-context。

3.如果不能控制Anctivity中非静态内部类的生命周期,那么使用静态内部类,并在其中对activity进行WeakReference(弱引用)。解决这个问题的方法是使静态内部类,并且对它的外部类有一个弱引用。例如ViewRoot中内部类W所做的那样。

4.垃圾回收器不是处理内存泄漏的保障。




你可能感兴趣的:(android)