以下是对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. Android应用程序内存优化
  2. Android保证首次获取到的location对象不为空的解决方案
  3. android加载字体内存泄漏的处理方法
  4. Android进程保活(常驻内存)
  5. Android性能优化(2):常见内存泄漏与优化(二)

随机推荐

  1. Android(安卓)按键模拟输入事件和Monitor
  2. 新建项目时Android(安卓)studio Module说
  3. Android(安卓)Binder入门指南之getServic
  4. Android(安卓)初识Retrofit
  5. Android(安卓)中Tabhost选项卡的两种实现
  6. Android(安卓)studio:隐式Intent的使用方
  7. android手机端与web服务器之间的Json数据
  8. 【Android开发那点破事】Android(安卓)Ed
  9. Android(安卓)P Image编译
  10. Android(安卓)ADT插件配置