java - 如果重置回调,为什么Android会由于静态Drawable而泄漏内存?

标签 java android memory-leaks

我只是在关注这篇关于如何避免内存泄漏的文章:android developer blog 以下是使用的代码 fragment :

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

据说drawable有一个对textview的回调引用(间接对activity);这将在旋转时保留 - 因此内存泄漏。

我的查询 是,drawable 的回调不会在旋转时重置 - 它会获取新的 textview(它将保存新的上下文)..因此允许以前的 textview 实例/要进行 GC 处理的上下文。

编辑:我得到的答案是关于如何“解决”问题的——我不是在寻找那个!请重新阅读查询。我正在添加更多细节。 启动 Activity 时,引用是:

Drawable1 -> TextView1 -> Activity1

旋转时,Activity1和TextView1被销毁,但Drawable1不被销毁

Drawable1 -> TextView2 -> Activity2

这意味着,Activity1 和 TextView1 可以自由地进行 GC 处理 - 因为没有其他对象引用它们。那么什么是泄漏?

我的理解错了吗?还是 Drawable 可以有多个 View 作为回调? (查看源代码,我没有看到 Drawable 上的回调列表)。

最佳答案

如果您旋转设备,将重新创建相同的 MyActivity 类(或您为其指定的任何名称),回调将被覆盖并且泄漏一直存在到下一次 GC .问题在于当您导航到另一个 Activity 时,保留对旧 Activity 的引用。如今,这已得到缓解,因为 setCallback 现在将回调存储在 WeakReference 中,如您在 current Drawable code 中所见。 , 但这是一个很强的引用 once (搜索 setCallback(Callback cb))。 无论如何,你是对的,如果你只看一个 Activity ,轮换后回调将被重置。

(编辑,添加段落): 例如:MainAcivity@1 是第一个实例。当您旋转时,它会被销毁并创建一个新的 MainActivity@2。一开始有泄漏,但是一旦sDrawable被重新赋值,MainActivity@1就可以自由收集了,没有问题。现在假设您导航到 SecondActivity,而不是旋转。现在,sDrawable 仅用于 MainActivity,并且仍然持有对 MainActivity@2 的引用,因此它会泄漏。

查看这段代码:

package com.douglasdrumond.leaky;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.widget.TextView;

public class MainActivity extends Activity {
    private static Drawable sBackground;

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

        TextView label = new TextView(this);
        System.gc();
        long memory = Runtime.getRuntime().totalMemory()
                - Runtime.getRuntime().freeMemory();
        label.setText("Memory: " + memory / 1024f);

        if (sBackground == null) {
            sBackground = getResources().getDrawable(R.drawable.large_bitmap);
        }
        label.setBackgroundDrawable(sBackground);

        setContentView(label);
    }

}

显然,旋转不会增加内存使用量。

关于java - 如果重置回调,为什么Android会由于静态Drawable而泄漏内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20138254/

相关文章:

java - 用于删除字符串数组中重复项的内置方法

Android 位图工厂内存不足第二张照片

ios - 阻止 iOS 7 MKMapView 泄漏内存

java - 如何停止由 org.asynchttpclient 创建的线程以防止内存泄漏?

java - 返回 String 类型的结果 (Java)

java - Scala Spark - java.lang.UnsupportedOperationException : empty. init

android - 如何在 Intellij 中自动构建和部署到多个 Android 设备

AndroidX 错误 : Both old and new data binding packages are available in dependencies

java - Jdbc和Tomcat疑似内存泄漏

java - 两种相同方法的性能差异