这会导致内存泄漏吗?

时间:2017-06-12 06:38:22

标签: 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();
    }
}

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

1 个答案:

答案 0 :(得分:0)

只是为了更新我发现的内容,以便其他人可以从中受益。我进一步修改了代码以进一步说明这一点:

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 - 这表明确实发生了垃圾收集以删除这些匿名类对象。

因此,我的结论是匿名类对象可以保存属于其封闭类对象的任何内容的引用。当匿名类对象持有某个甚至其封闭类对象不再持有的东西的引用时,它也将失去对它的引用。在某种意义上,匿名类对象持有其封闭类对象的弱引用,属于封闭类对象的任何对象引用都是从封闭类派生的(例如,enclosingClassField对象在示例中。)

相关问题