正确的onDestroy()/如何避免内存泄漏

Fab*_*ndl 13 android memory-leaks view android-activity

我阅读了一些关于如何避免Android内存泄漏的文章,但我仍然不确定我是否做对了.

  1. 我的应用程序由一个单独组成Activity.
  2. 我在该Activity中没有任何私有或静态成员,所有代码都是从内部启动的onCreate().
  3. 有一些自包含的静态类,其静态实例有时会包含对a ContextViews的引用 .在我的onDestroy()方法中,我将所有这些实例设置为null.
  4. 我回收了所有Bitmap的东西.

Q1:那够了吗?

令我困惑的是你可以在网上找到的禁忌的经典例子(http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/):

@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);

  TextView label = new TextView(this);
  label.setText("Leaks are bad");

  setContentView(label);
}
Run Code Online (Sandbox Code Playgroud)

我认为,一旦onCreate完成,label就会超出范围并进行GCed.

Q2:这怎么会造成内存泄漏?

我的活动基本上是这样的:

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /* Statics */
    AssetUtils.initIndex(this);
    BitmapLoader.startInstance(this);

    /* frame */
    ViewGroup frame = (ViewGroup) getLayoutInflater().inflate(R.layout.frame, null);
    this.setContentView(frame);

    /* create controller */
    Controller controller = new Controller(frame, getLayoutInflater());

    /* START */
    controller.start();
}

@Override
public void onDestroy() {
    super.onStop();

    /* Statics */
    AssetUtils.destroyInstance();
    BitmapLoader.destroyInstance();
}
Run Code Online (Sandbox Code Playgroud)

里面Controller我偶尔检索Context使用View#getContext()通过它来手动创建ViewS等.它永远不会静态存储在某个地方,只会存在于所有类的所有类的成员变量中Controller.

Q3:有什么我忽略的吗?

Sim*_*mon 22

Q1.你已经脱离了背景(没有开玩笑:)

如果您看到原始文章,泄漏实际上发生在引入位图字段的下一个代码片段中.Roman然后清楚地解释了为什么泄漏.您显示的代码不会泄漏.

http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/

Q2.仅在没有其他选择的情况下使用Activity上下文,并且绝不允许在范围大于其引用的Activity范围的内容中引用它.你所展示的代码并没有泄漏,因为没有任何上下文引用的范围大于你的Activity.你怀疑它吗?

Q3.当使用Bitmaps,静态引用或不使用静态引用时,我习惯在onPause()中从视图中取消绑定Bitamps(请记住onDestroy()不能保证,但它有点无关紧要,好像你被摧毁一样,你的进程被杀了所以GC不是一个问题).链接的文章还解释了如何执行此操作.我已将其作为处理位图的任何活动的模板模式.

[编辑]

对不起,我刚刚检查过.这篇文章没有说明如何解开.这是我使用的模式:

@Override
protected void onPause()
{
        super.onPause();

        unbindDrawables(findViewById(R.id.mainLayout));
        System.gc();
}


@Override
protected void onDestroy()
{
        super.onDestroy();

        unbindDrawables(findViewById(R.id.mainLayout));
        System.gc();
}

private void unbindDrawables(View view)
{
        if (view.getBackground() != null)
        {
                view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup && !(view instanceof AdapterView))
        {
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
                {
                        unbindDrawables(((ViewGroup) view).getChildAt(i));
                }
                ((ViewGroup) view).removeAllViews();
        }
}
Run Code Online (Sandbox Code Playgroud)

mainLayout 是Activity布局的根视图.

我包括onDestroy()因为我可能手动完成()我的Activity.

注意.调用system.gc()是一个复杂的主题,您可能想要省略它.这里有一些很好的讨论为什么它可能不是一件好事,主要关注性能.但是,在我看来,当一项活动被破坏时,暗示现在是执行GC的好时机不会造成伤害.在不必要地调用它的低效率将在破坏活动的开销中丢失.

  • 取消绑定Drawables是一个很好的解决方案,但System.gc()是一个基本破坏代码的指标.你不知道你在运行什么样的垃圾收集器.你不知道它会做什么.它甚至不能保证做任何事情.JVM可能完全忽略您的请求."你不知道它会做什么","你不知道它是否会有所帮助"和"你不应该再打电话"的组合是人们如此强烈地说这一点的原因.你不应该叫它. (3认同)