正确的 onDestroy()/如何避免内存泄漏 [英] Proper onDestroy() / How to avoid memory leaks

查看:24
本文介绍了正确的 onDestroy()/如何避免内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I read a number of articles on how to avoid memory-leaks in Android, but i'm still not quite sure if I got it right.

  1. 我的应用程序由一个 Activity 组成.
  2. 我在那个 Activity 中没有任何私有或静态成员,所有代码都是从 onCreate() 开始的.
  3. 有一些自包含的静态类,它们的静态实例有时包含对 ContextView 的引用.在我的 onDestroy() 方法中,我将所有这些实例设置为 null.
  4. 我回收了我所有的Bitmap.
  1. My Application consists of a single Activity.
  2. I don't have any private or static members in that Activity, all code is started from within onCreate().
  3. In have some self-contained static classes whose static instances sometimes hold references to a Context or Views. In my onDestroy() method, I set all of these instances to null.
  4. I recycle all of my Bitmaps.

Q1:够了吗?

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

What confuses me is the classic example of a no-go you can find on the net (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);
}

我认为,一旦 onCreate 完成,label 就会超出范围并被 GC.

I thought that, as soon as onCreate finishes, label goes out of scope and is GCed.

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

Q2: How can this create a memory-leak?

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

My Activity basically looks like this:

@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();
}

Inside Controller 我偶尔会使用 View#getContext() 检索一个 Context 将它传递给手动创建的 View> 之类的.它永远不会静态地存储在某个地方,只存储在类的成员变量中,这些变量都返回到 Controller.

Inside Controller I occasionally retrieve a Context using View#getContext() to pass it to manually created Views and the like. It's never stored statically somewhere, only in member-variables of classes which all go back to Controller.

Q3:有什么我忽略的地方吗?

Q3: Is there something I overlooked?

推荐答案

Q1.你已经断章取意了(无意开玩笑:)

Q1. You've taken this out of context (no joke intended :)

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

If you see the original article, the leak actually occurs in the next fragment of code where the Bitmap field is introduced. Roman then clearly explains why it leaks. The code you have shown will NOT leak.

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

第 2 季度.仅在没有其他选择的情况下使用 Activity 上下文,并且永远不允许在范围大于它引用的 Activity 范围的内容中引用它.就我所见,您显示的代码没有泄漏,因为没有任何上下文引用的范围大于您的 Activity.你怀疑它吗?

Q2. Use Activity context only where there is no other choice and NEVER allow a reference to it in something with a scope greater than the scope of the Activity it references. The code you've shown doesn't leak as far as I can see since nothing has a context reference with a scope greater than your Activity. Do you suspect that it does?

第三季度.无论是否使用位图,静态引用与否,我都习惯于在 onPause() 中从视图中解除绑定 Bitamps(请记住 onDestroy() 不能保证,但这有点不相关,就像您被销毁一样,您的进程被杀死因此 GC不是问题).链接的文章还解释了如何执行此操作.我已将其作为任何处理位图的活动的模板模式.

Q3. When using Bitmaps, static references or not, I am in the habit of unbinding Bitamps from Views in onPause() (remember onDestroy() is not guaranteed but it's kind of irrelevant as if you're being destroyed, your process is killed so GC isn't a concern). The linked article also explains how to do this. I have made it a template pattern for any of my Activities handling Bitmaps.

抱歉,我刚刚查了一下.文章没有展示如何解绑.这是我使用的模式:

Sorry, I just checked. The article does not show how to unbind. Here's the pattern I use:

@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();
        }
}

mainLayout 是 Activity 布局的根视图.

mainLayout is the root view of the Activity layout.

我包含 onDestroy() 因为我可能会手动完成 () 我的活动.

I include onDestroy() since I might manually finish() my Activity.

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

Note. Calling system.gc() is a complex subject and you might want to omit it. There are some good discussions on here why it might not be a good thing to do, principally concerned with performance. However, in my view, when an activity is being destroyed, hinting that now is a good time to perform GC can do no harm. The inefficiency of calling it unnecessarily will be lost in the overheads of destroying an activity.

这篇关于正确的 onDestroy()/如何避免内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆