为什么对Context的引用是内存泄漏?

时间:2017-01-16 23:16:41

标签: java android android-activity memory-leaks

根据Romain Guy,这种代码很容易因内存泄漏而导致

  

....观点引用了整个活动,因此也是如此   你的活动所持有的任何东西;通常是整个视图   层次结构及其所有资源。

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

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

  setContentView(label);
}  

我不清楚这一点 假设具有1个活动的应用程序,这是最长寿命的对象,可以根据需要重新创建。这意味着它的所有实例字段(可以且通常都是View)在任何时候都可以为空 任何静态实例字段都将与活动本身保持相同的持续时间 那么我们如何使用上面或下面的代码来获取内存泄漏:

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

2 个答案:

答案 0 :(得分:10)

  

假设应用程序具有1个活动,则这是最长寿命的对象

不,不是。您的流程中还有其他对象(例如,Application,内容提供商)将比活动实例更长。

请注意,默认情况下,在配置更改(例如,屏幕旋转)时,活动会被销毁并重新创建。

  

任何静态实例字段都将与活动本身保持相同的持续时间。

没有。只要过程在周围,静态字段就会出现。您的活动实例可能比这更短。

  

那么我们如何使用上述或以下代码获取内存泄漏:

您的第一个示例中没有静态字段。

Romain Guy在the blog post that you linked to中解释了第二种情况:

  

这段代码非常快,也非常错误;它泄漏了第一次屏幕方向更改时创建的第一个活动。将Drawable附加到视图时,视图将设置为drawable上的回调。在上面的代码片段中,这意味着drawable具有对TextView的引用,TextView本身具有对活动(Context)的引用,而Activity又引用了几乎任何东西(取决于您的代码。)

而且,如果您将LeakCanary添加到项目中,您会看到泄漏。

所以,让我们来看看:

  • 用户点按应用的主屏幕启动器图标,该图标与此活动相关联
  • 您的流程已开始
  • 您的活动实例已创建,然后使用onCreate()
  • 进行调用
  • sBackgroundnull,因此您可以为其指定getDrawable()结果
  • 您的活动用户界面将显示在屏幕上
  • 用户打喷嚏并意外旋转设备屏幕作为对打喷嚏作出反应的一部分
  • 您的旧活动实例已销毁
  • 创建一个新的活动实例,然后使用onCreate()
  • 调用
  • sBackground 不是null ,因此您单独留下sBackground

你有泄漏。正如Romain所解释的那样,sBackground对您的原始活动实例有一个非常明显的引用。因此,现在您有两个此活动的未完成实例:泄漏的原始文件,以及由于配置更改而创建的新原始实例。

答案 1 :(得分:0)

TLDR 自 2010 年以来,这不再是内存泄漏。另外,我会说这是 Android 中的一个错误(内存泄漏)(因为此参考是一个实现细节),而不是在你的应用程序。我们甚至不知道 setBackgroundDrawable(已弃用,支持 setBackground)调用 setCallback,它设置了对 view 的强引用。 Here 我解释了为什么 Drawable 无论如何都引用了 View


Romain Guy 在 2010 中对库进行了修复,以防止使用 WeakReference 导致内存泄漏,因此多年来这一直不是问题:< /p>

enter image description here