3

我在我的 Android 应用程序中遇到了报告的内存泄漏,经过一番调查,我几乎找到了泄漏的位置,这里是简化的代码:

public class LeakTracker {
    public static List<Callback> callbacks = new ArrayList<>();
    public static List<WeakReference<LeakingActivity>> weakList = new ArrayList<>();

    // causes leak of activity
    public void startLeak(final LeakingActivity activity) {
        callbacks.add(new Callback() {
            // remove this line then no leak
            Wrapper wrapper = new Wrapper(activity);
            @Override
            public void onCall() {
            }
        });
    }

    // no leak here
    public void startLeak2(final LeakingActivity activity) {
        weakList.add(new WeakReference<>(activity));
    }

    public interface Callback {
        void onCall();
    }

    static class Wrapper {
        private WeakReference<LeakingActivity> weakReference;

        public Wrapper(final LeakingActivity activity) {
            weakReference = new WeakReference<LeakingActivity>(activity);
        }
    }
}

发生泄漏是因为我调用了一个函数“startLeak”。活动变量将被泄露。但是,如果我调用“startLeak2”,则不会发生泄漏。我想知道为什么在第一种情况下会有泄漏。Wrapper 也使用 Wea​​kReference。

LeakActivity 类占用大约 30M 的内存。在 Android 设备上调用 startLeak 大约 5 次会导致 OOM。调用 startLeak2 不会。如果使用 startLeak 而不是 startLeak2,LeakCanary 工具会报告泄漏。

4

1 回答 1

1

在第一个方法中,您已将活动声明为 final。这会将活动的引用添加到Callback实例中,因此Wrapper泄漏的不是那个,而是它Callback本身。

另外,请记住,这Callback是一个匿名内部类,它还将包含对外部类的引用LeakTracker

于 2018-04-13T20:39:14.640 回答