根据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);
}
答案 0 :(得分:10)
假设应用程序具有1个活动,则这是最长寿命的对象
不,不是。您的流程中还有其他对象(例如,Application
,内容提供商)将比活动实例更长。
请注意,默认情况下,在配置更改(例如,屏幕旋转)时,活动会被销毁并重新创建。
任何静态实例字段都将与活动本身保持相同的持续时间。
没有。只要过程在周围,静态字段就会出现。您的活动实例可能比这更短。
那么我们如何使用上述或以下代码获取内存泄漏:
您的第一个示例中没有静态字段。
Romain Guy在the blog post that you linked to中解释了第二种情况:
这段代码非常快,也非常错误;它泄漏了第一次屏幕方向更改时创建的第一个活动。将Drawable附加到视图时,视图将设置为drawable上的回调。在上面的代码片段中,这意味着drawable具有对TextView的引用,TextView本身具有对活动(Context)的引用,而Activity又引用了几乎任何东西(取决于您的代码。)
而且,如果您将LeakCanary添加到项目中,您会看到泄漏。
所以,让我们来看看:
onCreate()
sBackground
为null
,因此您可以为其指定getDrawable()
结果onCreate()
sBackground
不是null
,因此您单独留下sBackground
你有泄漏。正如Romain所解释的那样,sBackground
对您的原始活动实例有一个非常明显的引用。因此,现在您有两个此活动的未完成实例:泄漏的原始文件,以及由于配置更改而创建的新原始实例。
答案 1 :(得分:0)
TLDR 自 2010 年以来,这不再是内存泄漏。另外,我会说这是 Android 中的一个错误(内存泄漏)(因为此参考是一个实现细节),而不是在你的应用程序。我们甚至不知道 setBackgroundDrawable
(已弃用,支持 setBackground
)调用 setCallback
,它设置了对 view
的强引用。 Here 我解释了为什么 Drawable
无论如何都引用了 View
。
Romain Guy 在 2010 中对库进行了修复,以防止使用 WeakReference
导致内存泄漏,因此多年来这一直不是问题:< /p>