2017-06-12 245 views
1

我最近讀了一些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()第二次將導致封閉類失去一審參考。此時,是否有資格進行垃圾回收?

+0

當你用匿名共享你的類變量時發生內存泄漏(並且在使用後不要將它們取消設置) – FieryCat

+0

嗯,我在匿名類中添加了'private double [] memoryLoad = new double [9999999];'看起來像我的機器上的JVM在內存消耗達到2.9GB之後做垃圾回收。所以看起來好像我回答了我自己的問題...... – Jai

+0

好的問題已經是答案的一半:) – FieryCat

回答

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對象)派生而來的。

相關問題