以下是对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的类和方法。

@Overrideprotected 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;  @Overrideprotected 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. 垃圾内存回收器并不能保证防止内存泄露。

更多相关文章

  1. 类和 Json对象
  2. Android中文API(144) —— JsonWriter
  3. Android之Handler用法总结
  4. android通过ksoap2对webservice的解析
  5. Android(安卓)View的介绍和使用
  6. Android中,把XML文件转换成Object对象的方法
  7. 【android测试】值得学习的android测试知识连接
  8. Android(安卓)获取内存信息
  9. Android中使用Gson解析JSON数据

随机推荐

  1. 深入探讨Android----必不可少的高级功能
  2. 一个轻量级、高可用性的 Android 版本更
  3. Android中图像变换Matrix的原理应用
  4. 基于ffmpeg+opengl+opensl es的android视
  5. Android蓝牙开发简介
  6. 提升Android开发效率的最佳实践
  7. Android中添加自定义按键 ---- 非标准做
  8. Android 动态加载布局文件
  9. android 服务的应用,在Activity中实现背景
  10. Android(安卓)N预览版 权限上的一些改变