Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/185.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 对局部变量的匿名类隐藏引用_Java_Android_Java Memory Leaks - Fatal编程技术网

Java 对局部变量的匿名类隐藏引用

Java 对局部变量的匿名类隐藏引用,java,android,java-memory-leaks,Java,Android,Java Memory Leaks,我在Android应用程序中遇到了一个内存泄漏报告,经过一些调查后,我基本上找到了泄漏的位置,以下是简化代码: public class LeakTracker { public static List<Callback> callbacks = new ArrayList<>(); public static List<WeakReference<LeakingActivity>> weakList = new ArrayList

我在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);
        }
    }
}
公共类泄漏跟踪器{
public static List callbacks=new ArrayList();
public static List weakList=new ArrayList();
//导致活动泄漏
公共无效警报(最终泄漏活动){
add(新回调(){
//拆下此管路,然后确保无泄漏
包装器=新包装器(活动);
@凌驾
公用电话{
}
});
}
//这里没有漏洞
公共设施2(最终泄漏活动){
weakList.add(新的WeakReference(活动));
}
公共接口回调{
void onCall();
}
静态类包装器{
私人WeakReference WeakReference;
公共包装器(最终泄漏活动){
weakReference=新的weakReference(活动);
}
}
}
泄漏发生是因为我调用了一个函数“starteak”。活动变量将被泄漏。然而,如果我称之为“惊人的2”,泄漏就不会发生。我想知道为什么第一个案例会有漏洞。包装器也使用WeakReference


LeakActivity类占用大约3000万内存。在Android设备上呼叫Starteak大约5次会导致OOM。打电话给Strateakeak2是不行的。如果使用StartEak而不是StartEak2,则LeakCanary工具会报告泄漏。

在您声明活动最终结果的第一个方法中。这将向
回调
实例添加活动引用,因此泄漏的不是
包装
,而是
回调
本身


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

检查的引用(在调试器中)如果
回调
的实例有一个私有字段,其中包含对
活动的引用
。它表示回调中有这样一个引用:LeakTracker$1.val$activity。我想可能有。我不明白为什么编译器会在那里放一个引用。从我的人的角度看,没有明显的必要。而且去掉包装纸的东西会使参考消失。是的,那就是你的漏洞。有趣的是,我在“普通”Java中尝试过(我不是Android开发人员),并且在匿名类的实例中没有任何对局部变量的引用。我猜编译器认为
Callback
需要活动,并创建隐藏字段来引用它。当变量直接用于匿名类时,我在“普通”Java中也看到了这一点。但在这种情况下不是这样。我的猜测是,与“普通”Java相比,Android编译器并没有那么优化。但如果您只是删除“Wrapper=newwrapper(activity);”,那么对activity的最终局部变量的引用就消失了。看起来这使得编译器添加了一个从回调到活动的隐藏引用则内部类
回调
未使用任何活动实例。因此,它不会有对活动的隐藏引用。尝试删除该行,并在
oncall()中使用活动实例。这也会使编译器将活动的隐藏引用添加到
回调
,因此它会像您的示例一样泄漏。隐藏引用来自回调,而不是包装器。注意包装器是静态的,并且包装器没有保留对活动的强引用。回调具有对LeakTracker的隐藏强引用。但这里泄漏的是最终的局部变量活动。不是LeakTracker。@darklord引用不在
回调的实现中
-如果这些是正常情况(不使用匿名类),那么是的,就不会有强引用。但在这种情况下,局部变量被捕获了,尽管我还没有测试来证明Drilon的理论,但我不会怀疑这是原因。