2017-04-27 8 views
2

JDK 8では、次のコードを実行した結果、毎回Aがファイナライズされることがわかりました。最後にprintlnをコメント解除すると、Aは決してファイナライズされません。メインスレッドで使用されているオブジェクトのファイナライズ

public class A { 
    @Override protected void finalize() { 
     System.out.println(this + "object is eligible for garbage collection"); 
    } 

    public static void main(String[] args) { 
     A a = new A(); 
     System.out.println("Main thread created object " + a); 
     for (int i = 0; i < 1000000000; i++) { 
      if (i % 100000000 == 0) 
       // Force GC 
       System.gc(); 
     } 
     //If i un-comment below it won't do garbage collection ever 
     // System.out.println(a + "is residing on heap and is alive"); 
    } 
} 

いくつかのいずれかは、それがその後、確定していない理由を、)(syso後に何が起こるのか、私にこの動作を説明することができます。

+0

あなたは 'gc'' A'を行うときに、なぜあなたは私がガベージコレクション –

+0

* *によってひとつひとつの時間を意味していますが使用されていません。あなたが 'a'をまだ使用中であるとコメントを外す場合 –

+5

の100%保証を意味する一つ一つの時間では –

答えて

0

JVMの最終バージョンでのガベージコレクションは、実行されたプログラムでオブジェクトが有効範囲外かどうかを判断するための最適化された原則に従います。
ほとんどの場合、メソッドの範囲に制限されていません。 Oracle documentationから

自動ガベージコレクションとは何ですか?

自動ガーベジコレクションは が使用中であり、どのされていないオブジェクトの識別、及び 未使用のオブジェクトを削除する、ヒープメモリを見てのプロセスです。使用中オブジェクトまたは参照オブジェクトは、 オブジェクトへのポインタを維持しているプログラムの一部を意味する を意味します。使用されていないオブジェクト、または参照されていないオブジェクトは、プログラムのどの部分でも参照されていない です。したがって、参照されていないオブジェクトである によって使用されるメモリを再利用することができます。

2つの最後の文章の事項:

未使用のオブジェクト、または参照されないオブジェクトは、もはやあなたのプログラムのどの部分によって参照されていません。したがって、参照されていないオブジェクトによって使用されるメモリを再利用することができます。あなたのサンプルコードで

System.gc();が呼び出されたときにゴミが要求を解放するためにそれをマークして集めるよう

public static void main(String[] args) { 
    A a = new A(); 
    System.out.println("Main thread created object " + a); 
    for (int i = 0; i < 1000000000; i++) { 
     if (i % 100000000 == 0) 
      System.gc(); 
    } 
} 

aはもはやあなたのプログラムのどの部分によって参照されます。

System.out.println(a + "is residing on heap and is alive"); }を追加すると、ファイナライザが呼び出されないことがあります。 gc()が引き続き呼び出されるときにgc()が呼び出されるときには呼び出されませんが、sysoutはプログラムの最後の行でもあります。

aインスタンスは、メインスレッドクラス(A)のインスタンスです。
メインスレッドが終了すると、現在のJVMプロセスは停止しています。
これらの条件では、その方法はおそらく実行する方法がありません。

Ps:複数の編集を申し訳ありません。私は...私の携帯電話にaforループの前にGC用資格で追加System.out.println(a + "is residing on heap and is alive");ライン、なし

+0

いいえ、そのスコープに関連していません以下の私の答えを見つけてください。 –

+1

@Show Stopper私は使用しているセマンティクスに同意します。 – davidxxx

0

ています。あなたの質問が言っていることに反して、メインスレッドはもう使用していません。それがGCであるかどうか(ファイナライザが実行されているかどうか)は気にするものではありません。 GCの動作について前提とするコードを記述することはできません。

コメントアウトされた行では、aは、その後までJVMが終了し、少なくともあなたのケースではファイナライザが実行されていないため、GCの対象になりません。

これはすべて正常な動作ですが、わかっているようにyou can't trust that the finalizers will or will not be runです。異なる環境で異なる結果が生じることがあります。

+0

この回答に加えて、ファイナライザは特定の順序で実行されず、オブジェクトのGCを大幅に遅らせるため、Javaヒープへの圧力を強く加えます。ファイナライザで費やされる時間は、ドメインロジックで費やされない時間です。ファイナライザは、Javaのニトログリセリンであり、有用であるが、非常に不安定で毒性があり、軽く使用することを意図していない。 –

+0

'foo'がフィールド' final int x'を持つ場合、JITは 'System.out.println(" x == "+ x)を置き換えることができます。 ..遅い計算..; System.out.println( "x ==" + x); '' int temp = foo.x; System.out.println( "x ==" + temp); ..遅い計算..; System.out.println( "x ==" + temp); '?もしそうなら、 'foo'を生かしておく必要がありますか? – supercat

+0

@supercatそれはJLSの私の理解を超えています。私はそれについて心配しなければならない状況に私を入れるコードを書こうとしないでください:) – Kayaman

0

スコープは、名前の妥当性を判断する言語の概念です。オブジェクトがガベージコレクション可能かどうかは、到達可能かどうかによって決まります。

JLSは§12.6.1言う:

到達可能なオブジェクトは、任意のライブスレッドから任意の潜在的 継続計算にアクセスすることができる任意のオブジェクトです。

JDK 8 GAでは、これは毎回完了します。最後にprintlnのコメントを外すと、決して確定されません。

コードがループに到達すると、スレッドがaにアクセスできる可能性はありません。したがって、到達不能であるため、ファイナライズとガベージコレクションが行われます。

注:名前aは、囲みブロック内のどこでもaを使用できるため、有効範囲内にあります。厳密な範囲規則は、JLS§6.3で網羅されています。しかし、実際にはわかるように、スコープは到達可能性やガベージコレクションとは関係ありません。

+0

スコープはコンパイル時のものですが、到達可能性は実行時のものです。 – Kayaman

関連する問題