【Android入门】防止ANDROID内存泄漏(翻译自Android Developers Blog)

原文请点击此处


原文作者: Romain Guy

 

Android applications are, at least on the T-Mobile G1, limited to 16 MB of heap. It's both a lot of memory for a phone and yet very little for what some developers want to achieve. Even if you do not plan on using all of this memory, you should use as little as possible to let other applications run without getting them killed. The more applications Android can keep in memory, the faster it will be for the user to switch between his apps. As part of my job, I ran into memory leaks issues in Android applications and they are most of the time due to the same mistake: keeping a long-lived reference to a Context .

 

Android 应用程序被限制最多使用16MB的堆空间,至少在T-Mobile G1上是这样。这对电话而言是很多空间,但对目前程序员想要得到的而言却很少的可怜。哪怕你没有打算使用这些给定的空间。你也应该尽可能的少用而留给其他应用程序更多的空间以免他们挂了。Android在内存中能存储越多的应用,用户在应用间的切换速度也就越快。作为我工作的一部分,我研究了一下Android应用程序的内存泄漏问题,发现他们大部分源于同一个错误:保留了一个长时间生存的上下文Context的引用。

 

On Android, a Context is used for many operations but mostly to load and access resources. This is why all the widgets receive a Context parameter in their constructor. In a regular Android application, you usually have two kinds of Context , Activity and Application . It's usually the first one that the developer passes to classes and methods that need a Context :

 

在Android上,许多操作都要用到Context,但大部分只是为了读取和访问资源。这就是为什么所有的Widgets都在构造函数Constructor中获得一个Context变脸作为输入参数。在一个普通的Android应用中,你通常有两种Context,活动Activity和应用Application.通常是程序员传递给那些需要Context的类或者方法的都是第一种Context:

 

 

This means that views have a reference to the entire activity and therefore to anything your activity is holding onto; usually the entire View hierarchy and all its resources. Therefore, if you leak the Context ("leak" meaning you keep a reference to it thus preventing the GC from collecting it), you leak a lot of memory. Leaking an entire activity can be really easy if you're not careful.

 

这意味着视图Views有一个整个Activity的引用也包括这整个Activity所包含的东西,通常是整个视图层次何所有它的资源。如果你泄漏了Context(泄漏 是指你保持一个引用并不让GC(垃圾回收机制)回收它)。你就会泄漏很多内存。如果你不小心一点那泄漏整个Activity都不是难事。

 

When the screen orientation changes the system will, by default, destroy the current activity and create a new one while preserving its state. In doing so, Android will reload the application's UI from the resources. Now imagine you wrote an application with a large bitmap that you don't want to load on every rotation. The easiest way to keep it around and not having to reload it on every rotation is to keep in a static field:

 

当屏幕的方向发生变化,系统默认会摧毁当前的Activity然后创建一个适合当前状态的新的Activity。Android将从资源中重新读取应用程序的界面UI来完成这个操作。现在想象你写了一个含有很大Bitmap的应用程序,你也不希望每次转动手机他都会重新读取一遍。最简单的方法就是把它设置在静态区域:

 

 

This code is very fast and also very wrong; it leaks the first activity created upon the first screen orientation change. When a Drawable is attached to a view, the view is set as a callback on the drawable. In the code snippet above, this means the drawable has a reference to the TextView which itself has a reference to the activity (the Context ) which in turns has references to pretty much anything (depending on your code.)

 

这个代码段运行起来很快,同时也是很有问题的。它把第一个由于屏幕转动创建的第一个Activity泄漏了。当一个Drawable对象被连接在视图上,这个视图就被设成drawable的一个回调.这对于上面的代码意味着,drawable有一个TextView的引用,而该TextView本身有个Activity的引用(Context),而这个引用依次又引用了几乎所有的东西(视具体代码而定)

 

This example is one of the simplest cases of leaking the Context and you can see how we worked around it in the Home screen's source code (look for the unbindDrawables() method) by setting the stored drawables' callbacks to null when the activity is destroyed. Interestingly enough, there are cases where you can create a chain of leaked contexts, and they are bad. They make you run out of memory rather quickly.

 

这个例子是最简单的泄露Context的案例,你可以看看在Home screen's source code里看看我们是如何通过在Activity被摧毁时设置drawable的回调函数为NULL来避开这个问题(查阅unbindRawables()方法)。还有很多例子展示你在什么地方可以创建一连串的泄露Contexts,而且他们都很有破坏性,他们能让你很快的用完内存。

 

There are two easy ways to avoid context-related memory leaks. The most obvious one is to avoid escaping the context outside of its own scope. The example above showed the case of a static reference but inner classes and their implicit reference to the outer class can be equally dangerous. The second solution is to use the Application context. This context will live as long as your application is alive and does not depend on the activities life cycle. If you plan on keeping long-lived objects that need a context, remember the application object. You can obtain it easily by calling Context.getApplicationContext() or Activity.getApplication() .

 

这有两种简单的方法来避免和Context有关的内存泄露。最显然的方法是避免使Context跑到他自己的范围之外。以上的例子展示了一个静态引用但是内部类和他们对外部类的隐式引用也可能同样危险。第二个解决方法是使用Application的Context。这个Context的寿命和你的应用程序一样长而且不依赖于Activity的生命周期。如果你计划保持一个需要Context的长寿命对象,记住可以通过Context.getApplicationContext()或者Activity.getApplication()来使用Application Context。

 

In summary, to avoid context-related memory leaks, remember the following:

 

总之,为了避免于Context有关的内存泄露,记住以下几点

  • Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself)
  • 不要保持一个长寿命的Activity的Context的引用(一个Activity的引用的寿命应该和这个Activity一样长)
  • Try using the context-application instead of a context-activity
  • 试试使用Application Context代替Activity Context
  • Avoid non-static inner classes in an activity if you don't control their life cycle, use a static inner class and make a weak reference to the activity inside. The solution to this issue is to use a static inner class with a WeakReference to the outer class, as done in ViewRoot and its W inner class for instance
  • 如果你不想控制他们的生命周期,避免在一个Activity内使用非静态的内部类,使用静态的内部类并且使用对Activity的弱引用。这个情况的做法是使用一个含有到外部的WeakReference的静态的内部类。就好像在ViewRoot和他的W内部类一样。
  • A garbage collector is not an insurance against memory leaks
  • 垃圾处理机制不是制服内存泄露的终极保险
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值