java - 这会导致内存泄漏吗?

标签 java memory-leaks anonymous-class

我最近读过一些 SO 帖子/答案,建议使用匿名类可能会导致内存泄漏。如果我理解正确的话,如果匿名类的对象引用泄漏到封闭类之外,则可能会导致该匿名类实例成为垃圾且不可收集。

为了确保我理解正确,我说下面的示例代码不会导致内存泄漏是否正确?

public class EnclosingClass {
    private AnonymousClassBase anonymous;

    public void startDoingSomething() {
        this.anonymous = new AnonymousClassBase() {
            @Override public void anonymouslyDoSomething() {
                EnclosingClass.this.doSomething("Did something anonymously!");
            }
        };
        this.anonymous.anonymouslyDoSomething();
    }

    private void doSomething(final String something) {
        System.out.println(something);
    }
}

public abstract class AnonymousClassBase {
    public abstract void anonymouslyDoSomething();
}

public class MainClass {
    private final EnclosingClass enclosing = new EnclosingClass();

    // Some kind of button click event handler
    public void onButtonClicked() {
        this.enclosing.startDoingSomething();
    }
}

私有(private)字段anonymous只能存储AnonymousClassBase的一个实例,因此第二次调用startDoingSomething()将导致封闭类丢失第一个实例的引用。此时,第一个实例是否有资格进行垃圾回收?

最佳答案

只是为了提供我发现的最新信息,以便其他人能够从中受益。我进一步修改了代码以进一步说明这一点:

public class EnclosingClass {
    private AnonymousClassBase anonymous;
    private Object enclosingClassField = new Object();

    public void startDoingSomething() {
        this.anonymous = new AnonymousClassBase() {
            // Takes some significant load on memory for each anonymous object
            private double[] memoryLoad = new double[9999999];

            // Just taking reference of something belonging to enclosing class
            private Object test = EnclosingClass.this.enclosingClassField;

            @Override public void anonymouslyDoSomething() {
                EnclosingClass.this.doSomething("Did something anonymously!");
            }
        };

        this.anonymous.anonymouslyDoSomething();
    }

    private void doSomething(final String something) {
        System.out.println(something);
    }
}

public abstract class AnonymousClassBase {
    public abstract void anonymouslyDoSomething();
}

public class MainClass {
    private final EnclosingClass enclosing = new EnclosingClass();

    // Some kind of button click event handler
    public void onButtonClicked() {
        this.enclosing.startDoingSomething();
    }
}

主要区别在于每个匿名对象将占用近 76.3MB 的内存负载。 JVM 慢慢增加到大约 2.9GB,然后下降到大约 300MB - 这表明确实发生了垃圾收集来删除那些匿名类对象。

因此我的结论是匿名类对象可以保存属于其封闭类对象的任何内容的引用。当匿名类对象持有某个对象的引用时,即使它的封闭类对象也不再持有该引用,那么它也将失去对该对象的引用。从某种意义上说,匿名类对象持有其封闭类对象的弱引用,并且属于封闭类对象的任何对象引用都是从封闭类派生的(例如示例中的enendingClassField对象)。

关于java - 这会导致内存泄漏吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44492827/

相关文章:

java - 我们可以为接口(interface)和抽象类创建对象吗?

java - 如何让两台计算机用java相互通信以进行即时通讯?

java - 如何在Eclipse程序中重定向输入和输出

ios - Twitter 和 Fabric 中的内存泄漏 - Swift

c - 双向链表释放内存 valgrind 错误

c - 在 C 中连接字符串指针时如何避免内存泄漏

java - 字符串的动态 if 语句

java - 将转义码(原始数据)发送到打印机的正确方法

c++ - 如何将模板类限制为仅具有类型别名的特定专业

java - 返回匿名类的新对象的方法