1

到達不能なオブジェクトを見つけた後、JVM gc がそのオブジェクトの finalize() メソッドを実行することを読みました。次に、オブジェクトがまだ到達できないかどうかを確認し、そうでない場合は削除します。そこで、オブジェクトの参照を再び利用できるようにするファイナライズを作成しました。

public class Stuff {

 List<Object> list;

 public Stuff(List<Object> list) {
  this.list = list;
 }

 @Override
 protected void finalize() throws Throwable {
  list.add(this);
  System.out.println("A Stuff is finalized");
 }
}

主な方法は次のとおりです。

public class Main { 
 public static void main(String[] args) {
  List<Object> list = new ArrayList<>();
  list.add(new Stuff(list));
  list.remove(0);
  System.gc();
  System.out.println(list.get(0));
 }
}

「A stuff is finalized」が標準出力に表示されるため、gc が実行されますが、その後メインの printline で IndexOutOfBoundsException がスローされます。これを機能させることはできますか?

私は通常、ファイナライズをまったく使用しません。ファイナライズがオブジェクトの参照を再び利用可能にすることができるかどうかを確認するのは興味深いと思いました。これを機能させることはできますか?

4

2 に答える 2

2

ファイナライザーは専用のファイナライザー スレッドで実行され、作成したものはスレッド セーフでないコードです。たとえば、同期コレクションを使用します。

もう 1 つの落とし穴は、呼び出しだけでSystem.gc()は、メソッド呼び出しが戻るまでにファイナライザーが実行されているという保証がないことです。ファイナライザーは、ファイナライザー スレッドのキューに入れられただけです。これを回避するには、 などの同期ヘルパーを実際に使用して、適切な手段として 2 ~ 3 回CountDownLatch呼び出す必要があります。System.gc()

ここで、上記のアイデアでコードが改善されました。

public class Stuff {

  static final List<Stuff> list = Collections.synchronizedList(new ArrayList<Stuff>());
  static final CountDownLatch cdl = new CountDownLatch(1);

  @Override protected void finalize() {
    list.add(this);
    cdl.countDown();
  }

  public static void main(String[] args) throws Exception {
    list.add(new Stuff());
    list.remove(0);
    System.gc();
    System.gc();
    cdl.await();
    System.out.println(list.size());
  }
}
于 2013-11-06T19:45:48.420 に答える
0
List<Object> list = new ArrayList<>();
  list.add(new Stuff(list));
  list.remove(0);
  System.gc();
  System.out.println(list.get(0));

実装されたクラスのインスタンスObjectのリストを作成しています。そう期待されます。LisStufffinalizeArrayIndexOutOfBound

于 2013-11-06T19:46:36.123 に答える