当前位置: 代码迷 >> Android >> Android 内存储器泄露
  详细解决方案

Android 内存储器泄露

热度:59   发布时间:2016-05-01 16:44:55.0
Android 内存泄露

android application被限制到16M堆内存。

越多的application保存在内存中,那么在他们之间切换的时候,速度就会更快。

a?Context?能被在很多方面应用,但是最多的是加载访问资源,这就是为啥widget接受一个a?Context?参数在构造函数里。

在一个规则的application中,你通常用俩中Context,activity和application。

当屏幕方向转变时,默认摧毁当前的activity 创建一个新的,android将重新加载application的ui。

如果你有一个大的bitmap你不想每次转变屏幕时都加载,如果你用一个static去总是保持它

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?);?}

代码很快,但是也很错。他泄露了这第一个activity,当一个drawable被?attached to a view,这个VIEW被设置作为一个callback在这个drawable,在上述代码中,这意味着这个drawable有一个引用在 textview,而这个textview本身有一个引用在这个activity上,而这个activity依次有许多他自身的引用。你可以参看home screen源代码通过设置drawble的callback为空当activity被摧毁时。

/** * Remove the callback for the cached drawables or we leak the previous* Home screen on orientation change. */

  private void unbindDrawables(ArrayList<ItemInfo> desktopItems) {        if (desktopItems != null) {            final int count = desktopItems.size();            for (int i = 0; i < count; i++) {                ItemInfo item = desktopItems.get(i);                switch (item.itemType) {                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                    ((ApplicationInfo)item).icon.setCallback(null);                    break;                }            }        }    }俩中避免与context相关联的内存泄露。The most obvious one is to avoid escaping the context outside of its own scope.上述例子展示了一个静态引用的例子。但是内部类和他们的隐士的外部引用能是同样危险的。这第二个解答是用application context。这个context将活着和你的application一样长,并不依赖这activity的生命周期。如果你计划保持长引用的对象,他需要一个context,记者用application的。通过Context.getApplicationContext()or Activity.getApplication()
  • 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)
  • Try using the context-application instead of a context-activity
  • 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

FAQ:

1.If Drawable just a member field and not static - it’s fine right?

An instance variable will not cause any problem indeed.

2.public void setBackgroundDrawable(Drawable d) {

if (d != null) {

d.setCallback(this);

}

}

从这个代码看出,上述例子里the setBackgroundDrawable reset the drawable’s callback after the activity reloaded.

when the setBackgroundDrawable() is called, the Drawable has setCallback() invoked, which will overwrite the current callback, therefore no memory leak?

  1. Romain Guy
    Jan 29th, 2009 at 3:25 pm

    Justin,

    If you always set it on a View, then it’s not an issue (well, except that you kept a hold onto the previous Context for longer than needed.) It can become very problematic for an application in which you use the drawables in a ListView for instance: as long as the drawable is not re-bound to a View, you keep the old Context and all the resources and Views. It’s much safer to not rely on that at all.

  2. 上述说了你不可能总是记者re-bound到一个VIEW上,一旦你忘了,就会泄露。
  3. 14?Romain Guy
    Jan 29th, 2009 at 3:26 pm

    There’s also the situation of when your Activity is destroyed but not recreated (it can happen for several reasons.) If the process is still there, your static fields also are and you are leaking the Activity until it is recreated.

  4. 这段话说了如果你的activity被摧毁但是没被创建,如果你的进程仍旧在哪,你的静态字段也在哪,那么你正在泄露。

  相关解决方案