2017-06-12 15 views
1

私は最近、匿名クラスを使用してメモリリークを引き起こす可能性があると思われる投稿/回答を読んでいます。私が正しく理解していれば、匿名クラスのオブジェクト参照が囲むクラス外に漏れると、その匿名クラスインスタンスがガベージコレクション不可能になる可能性があります。これはメモリリークを引き起こしますか?

ちょうど私が正しく理解したことを確認するために、以下のサンプルコードがメモリリークを引き起こさないと言ってもいいですか?

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はだけなのでstartDoingSomething()囲むクラスは、最初のインスタンスの参照を失うことになります二度目の呼び出し、AnonymousClassBaseの1つのインスタンスを格納することができます。この時点で、最初のインスタンスはガベージコレクションの対象ですか?

+0

クラス変数を匿名で共有しているときにメモリリークが発生します(使用後に解除しないでください) – FieryCat

+0

匿名クラスに 'private double [] memoryLoad = new double [9999999];を追加しましたメモリ消費量が2.9GBに達した後、私のマシン上のJVMがガベージコレクトをしたようです。だから私は自分の質問に答えたようだ... – 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.3メガバイトのメモリ負荷がかかることである:私はさらに、さらに点を説明するためのコードを変更しました。 JVMは約2.9GBまでゆっくりと増加し、約300MBに低下しました。これは、これらの匿名クラスオブジェクトを削除するためにガベージコレクションが行われたことを示しています。

私の結論は、匿名クラスオブジェクトは、その囲むクラスオブジェクトに属するものの参照を保持できるということです。匿名クラスオブジェクトが、その囲むクラスオブジェクトでも保持していないものの参照を保持している場合、その参照も失われます。ある意味では、匿名クラスオブジェクトは、その囲むクラスオブジェクトの弱参照を保持しており、囲むクラスオブジェクトに属するオブジェクト参照は、囲むクラスから導出される(例ではenclosingClassFieldオブジェクト)。

関連する問題