356

finalize()メソッドがで呼び出されるタイミングを知る必要がありJVMます。メソッドが呼び出されたときにファイルfinalize()をオーバーライドして書き込むテストクラスを作成しました。実行されません。実行されない理由を教えてもらえますか?

4

17 に答える 17

390

このfinalizeメソッドは、オブジェクトがガベージコレクションを取得しようとしているときに呼び出されます。これは、ガベージコレクションの対象になった後であればいつでも可能です。

オブジェクトがガベージコレクションされない(したがってfinalize呼び出されない)可能性は完全にあることに注意してください。これは、オブジェクトがgcの対象にならない場合(JVMの存続期間全体を通じて到達可能であるため)、またはオブジェクトが対象になり、JVMの実行が停止するまでの間にガベージコレクションが実際に実行されない場合に発生する可能性があります(これは、単純な場合によく発生します)。テストプログラム)。

まだ呼び出されていないオブジェクトで実行するようにJVMに指示する方法はありますがfinalize、それらを使用することもお勧めできません(そのメソッドの保証もそれほど強力ではありません)。

アプリケーションの正しい動作に依存しfinalizeている場合は、何か間違ったことをしていることになります。(通常はJava以外の)リソースのクリーンアップにのみfinalize使用する必要があります。これは、JVMがオブジェクトで呼び出されることを保証していないためです。finalize

于 2010-03-24T09:28:03.590 に答える
292

finalize()一般的に、クリーンアップなどを行うことに頼らないのが最善です。

Javadoc (読む価値がある)によると、それは次のとおりです。

ガベージコレクションがオブジェクトへの参照がこれ以上ないと判断したときに、オブジェクトのガベージコレクターによって呼び出されます。

Joachimが指摘したように、オブジェクトが常にアクセス可能である場合、これはプログラムの存続期間中には発生しない可能性があります。

また、ガベージコレクタは特定の時間に実行されることが保証されていません。一般的に、私が言おうとしているfinalize()のは、あなたがそれを必要とする特定の何かがない限り、おそらく一般的に使用するのに最適な方法ではないということです。

于 2010-03-24T09:30:41.927 に答える
76
protected void finalize() throws Throwable {}
  • finalize()すべてのクラスはjava.lang.Objectからメソッドを継承します
  • このメソッドは、オブジェクトへの参照が存在しないと判断したときにガベージコレクターによって呼び出されます。
  • Object finalizeメソッドはアクションを実行しませんが、任意のクラスによってオーバーライドされる可能性があります
  • 通常は、Java以外のリソースをクリーンアップする、つまりファイルを閉じるためにオーバーライドする必要があります
  • オーバーライドfinalize()する場合は、try-catch-finallyステートメントを使用し、常にを呼び出すことをお勧めしますsuper.finalize()。これは、クラスを呼び出すオブジェクトによって使用されるリソースを誤って閉じるのを見逃さないようにするための安全対策です。

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
    
  • ガベージコレクション中にスローされた例外finalize()は、ファイナライズを停止しますが、それ以外の場合は無視されます

  • finalize()どのオブジェクトでも2回以上実行されることはありません

引用元:http ://www.janeg.ca/scjp/gc/finalize.html

この記事も確認できます。

于 2010-03-24T09:31:09.410 に答える
26

Javafinalize()メソッドはデストラクタではないため、アプリケーションが依存するロジックを処理するために使用しないでください。Java仕様でfinalizeは、アプリケーションの稼働中にメソッドが呼び出される保証はありません。

おそらく必要なのは、次のように、finallyとクリーンアップ方法の組み合わせです。

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {
    if (null != myObj) {
        myObj.cleanup();
    }
}

MyClass()これにより、コンストラクターが例外をスローしたときの状況が正しく処理されます。

于 2010-03-24T09:29:30.750 に答える
20

効果的なJava、第2版の27ページ をご覧ください。項目7:ファイナライザーを避ける

ファイナライザーは予測不可能で、多くの場合危険であり、通常は不要です。ファイナライザーでタイムクリティカルなことは絶対にしないでください。重要な永続状態を更新するためにファイナライザーに依存することはありません。

リソースを終了するには、代わりにtry-finallyを使用します。

// try-finally block guarantees execution of termination method
Foo foo = new Foo(...);
try {
    // Do what must be done with foo
    ...
} finally {
    foo.terminate(); // Explicit termination method
}
于 2013-07-01T14:20:56.740 に答える
16

finalize()Javaでメソッドが呼び出されるのはいつですか。

Finalizeメソッドは、GCがオブジェクトに到達できなくなったことを検出した後、オブジェクトによって使用されているメモリを実際に再利用する前に呼び出されます。

  • オブジェクトが到達不能になることがない場合、オブジェクトfinalize()が呼び出されることはありません。

  • GCが実行されない場合finalize()は、呼び出されない可能性があります。(通常、GCは、JVMが、価値のあるものにするのに十分なガベージがある可能性が高いと判断した場合にのみ実行されます。)

  • GCが特定のオブジェクトに到達できないと判断するまでに、複数のGCサイクルがかかる場合があります。(Java GCは通常、「世代別」コレクターです...)

  • GCがオブジェクトが到達不能でファイナライズ可能であることを検出すると、そのオブジェクトはファイナライズキューに入れられます。ファイナライズは通常、通常のGCとは非同期に行われます。

(JVM仕様では、実際に、JVMがファイナライザーを実行することはできません...オブジェクトによって使用されるスペースを再利用しない場合。この方法で実装されたJVMは機能しなくなり、役に立たなくなりますが、この動作は「許可」されます。 。)

結果として、明確な時間枠内で実行する必要があることを実行するためにファイナライズに依存することは賢明ではありません。それらをまったく使用しないことが「ベストプラクティス」です。メソッドで実行しようとしていることを実行するためのより良い(つまり、より信頼性の高い)方法があるはずですfinalize()

ファイナライズの唯一の正当な使用法は、アプリケーションコードによって失われたオブジェクトに関連付けられたリソースをクリーンアップすることです。それでも、そもそもオブジェクトが失われないように、アプリケーションコードを記述してみてください。(たとえば、Java 7以降のtry-with-resourcesを使用して、close()常に呼び出されるようにします...)


finalize()メソッドが呼び出されたときにファイルをオーバーライドして書き込むテストクラスを作成しました。実行されません。実行されない理由を教えてもらえますか?

言うのは難しいですが、いくつかの可能性があります。

  • オブジェクトはまだ到達可能であるため、ガベージコレクションされません。
  • テストが終了する前にGCが実行されないため、オブジェクトはガベージコレクションされません。
  • オブジェクトはGCによって検出され、GCによってファイナライズキューに配置されますが、テストが終了する前にファイナライズは完了しません。
于 2010-03-24T09:28:50.073 に答える
10

JVMによるfinalize()メソッドの呼び出しには不確実性があるため(オーバーライドされるfinalize()が実行されるかどうかはわかりません)、研究目的では、finalize()が呼び出されたときに何が起こるかを観察するためのより良い方法は次のとおりです。コマンドによってJVMにガベージコレクションを呼び出すように強制しSystem.gc()ます。

具体的には、オブジェクトが使用されなくなったときにfinalize()が呼び出されます。しかし、新しいオブジェクトを作成してそれを呼び出そうとすると、その呼び出しの確実性はありません。したがって、確実に、将来使用されないオブジェクトを作成します。したがって、オブジェクトnullのfinalize呼び出しが表示されます。cc

class Car {

    int maxspeed;

    Car() {
        maxspeed = 70;
    }

    protected void finalize() {

    // Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
    // Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection

        System.out.println("Called finalize method in class Car...");
    }
}

class Bike {

    int maxspeed;

    Bike() {
        maxspeed = 50;
    }

    protected void finalize() {
        System.out.println("Called finalize method in class Bike...");
    }
}

class Example {

    public static void main(String args[]) {
        Car c = new Car();
        c = null;    // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
        Bike b = new Bike();
        System.gc();    // should clear c, but not b
        for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
            System.out.print("\t" + b.maxspeed);
            if (b.maxspeed > 50) {
                System.out.println("Over Speed. Pls slow down.");
            }
        }
    }
}

出力

    Called finalize method in class Car...
            1       2       3       4       5       6       7       8       9
    10      11      12      13      14      15      16      17      18      19
    20      21      22      23      24      25      26      27      28      29
    30      31      32      33      34      35      36      37      38      39
    40      41      42      43      44      45      46      47      48      49
    50      51Over Speed. Pls slow down.
            52Over Speed. Pls slow down.
            53Over Speed. Pls slow down.
            54Over Speed. Pls slow down.
            55Over Speed. Pls slow down.
            56Over Speed. Pls slow down.
            57Over Speed. Pls slow down.
            58Over Speed. Pls slow down. 
            59Over Speed. Pls slow down.
            60Over Speed. Pls slow down.
            61Over Speed. Pls slow down.
            62Over Speed. Pls slow down.
            63Over Speed. Pls slow down.
            64Over Speed. Pls slow down.
            65Over Speed. Pls slow down.
            66Over Speed. Pls slow down.
            67Over Speed. Pls slow down.
            68Over Speed. Pls slow down.
            69Over Speed. Pls slow down.
            70Over Speed. Pls slow down.

-70まで印刷した後、オブジェクトbがプログラムで使用されなくなった後でも、「クラスBike ...のfinalizeメソッドが呼び出されました」が印刷されないため、bがJVMによってクリアされるかどうかは不確実です。

于 2015-05-13T11:34:24.457 に答える
5

finalizeは、クラス作成のカウントを出力します。

protected void finalize() throws Throwable {
    System.out.println("Run F" );
    if ( checkedOut)
        System.out.println("Error: Checked out");
        System.out.println("Class Create Count: " + classCreate);
}

主要

while ( true) {
    Book novel=new Book(true);
    //System.out.println(novel.checkedOut);
    //Runtime.getRuntime().runFinalization();
    novel.checkIn();
    new Book(true);
    //System.runFinalization();
    System.gc();

ご覧のように。次の出力は、クラス数が36のときにgcが最初に実行されたことを示しています。

C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F
于 2012-11-24T23:17:31.390 に答える
4

最近(テスト中に接続プールを破棄するために)ファイナライザーの方法に取り組んできましたが、ファイナライザーには多くのことが欠けていると言わざるを得ません。VisualVMを使用して観察し、弱い参照を使用して実際の対話を追跡することで、Java 8環境(Oracle JDK、Ubuntu 15)では次のことが当てはまることがわかりました。

  • ファイナライズはすぐには呼び出されませんファイナライザー(GC部分)は個別に参照を所有します
  • デフォルトのガベージコレクタは、到達不能なオブジェクトをプールします
  • Finalizeは一括で呼び出され、ガベージコレクターがリソースを解放する特定のフェーズがあることを示す実装の詳細を示します。
  • System.gc()を呼び出すと、オブジェクトがより頻繁にファイナライズされることはなく、ファイナライザーが到達不能なオブジェクトをより迅速に認識するようになるだけです。
  • スレッドダンプを作成すると、ほとんどの場合、ヒープダンプまたはその他の内部メカニズムの実行中にヒープオーバーヘッドが高くなるため、ファイナライザーがトリガーされます。
  • ファイナライズシームは、メモリ要件(より多くのメモリを解放する)または特定の内部制限のファイナライズ拡張用にマークされているオブジェクトのリストのいずれかによってバインドされます。したがって、多数のオブジェクトがファイナライズされる場合、ファイナライズフェーズは、少数のオブジェクトと比較して、より頻繁かつ早期にトリガーされます。
  • System.gc()が直接ファイナライズをトリガーする状況がありましたが、参照がローカルで短命である場合に限りました。これは世代に関連している可能性があります。

最終的な考え

Finalizeメソッドは信頼性がありませんが、1つの目的にのみ使用できます。ガベージコレクションが行われる前にオブジェクトが閉じられたか破棄されたことを確認できるため、寿命の終わりのアクションを伴うより複雑なライフサイクルを持つオブジェクトが正しく処理された場合、フェイルセーフを実装できます。それが私が考えることができる1つの理由であり、それをオーバーライドする価値があります。

于 2015-09-25T11:08:13.987 に答える
2

finalizeメソッドは保証されていません。このメソッドは、オブジェクトがGCの対象になったときに呼び出されます。オブジェクトがガベージコレクションされない場合が多くあります。

于 2010-03-24T10:48:13.253 に答える
2

オブジェクトがライブスレッドまたは静的参照から到達できない場合、オブジェクトはガベージコレクションまたはGCの対象になります。つまり、すべての参照がnullの場合、オブジェクトはガベージコレクションの対象になります。循環依存は参照としてカウントされないため、オブジェクトAにオブジェクトBの参照があり、オブジェクトBにオブジェクトAの参照があり、他にライブ参照がない場合、オブジェクトAとBの両方がガベージコレクションの対象になります。通常、オブジェクトは次の場合にJavaでガベージコレクションの対象になります。

  1. そのオブジェクトのすべての参照は明示的にnullに設定されます(例:object = null)
  2. オブジェクトはブロック内に作成され、コントロールがそのブロックを終了すると、参照はスコープ外になります。
  3. オブジェクトが別のオブジェクトの参照を保持している場合、親オブジェクトをnullに設定し、コンテナオブジェクトの参照をnullに設定すると、子オブジェクトまたは含まれているオブジェクトが自動的にガベージコレクションの対象になります。
  4. オブジェクトにWeakHashMapを介したライブ参照のみがある場合、そのオブジェクトはガベージコレクションの対象になります。
于 2013-04-09T12:01:59.407 に答える
2

時々それが破壊されるとき、オブジェクトは行動を起こさなければなりません。たとえば、オブジェクトにファイルハンドルやフォントなどのJava以外のリソースがある場合、オブジェクトを破棄する前に、これらのリソースが解放されていることを確認できます。このような状況を管理するために、javaは「ファイナライズ」と呼ばれるメカニズムを提供します。それをファイナライズすることにより、オブジェクトがガベージコレクターから削除されようとしているときに発生する特定のアクションを定義できます。ファイナライザーをクラスに追加するには、finalize()メソッドを定義するだけです。Java実行時間は、そのクラスのオブジェクトを削除しようとするたびにこのメソッドを呼び出します。finalize method()内オブジェクトを破棄する前に実行するアクションを指定します。ガベージコレクターは、実行状態を参照しなくなったオブジェクト、または参照している他のオブジェクトを間接的に参照していないオブジェクトを定期的に検索します。アセットが解放される前に、Javaランタイムはオブジェクトのfinalize()メソッドを呼び出します。finalize()メソッドの一般的な形式は次のとおりです。

protected void finalize(){
    // This is where the finalization code is entered
}

protectedキーワードを使用すると、クラス外のコードによるfinalize()へのアクセスが防止されますfinalize()は、ガベージコレクションの直前に呼び出されることを理解することが重要です。たとえば、オブジェクトがスコープを離れるときは呼び出されません。これは、 finalize()がいつ実行されるか、または実行されるかどうかがわからないことを意味します。その結果、プログラムは、システムリソースまたはオブジェクトによって使用される他のリソースを解放するための他の手段を提供する必要があります。プログラムの通常の実行については、finalize()に依存しないでください。

于 2017-07-02T20:19:10.273 に答える
1

finalizeメソッドをオーバーライドするクラス

public class TestClass {    
    public TestClass() {
        System.out.println("constructor");
    }

    public void display() {
        System.out.println("display");
    }
    @Override
    public void finalize() {
        System.out.println("destructor");
    }
}

メソッドが呼び出されるfinalizeの可能性

public class TestGarbageCollection {
    public static void main(String[] args) {
        while (true) {
            TestClass s = new TestClass();
            s.display();
            System.gc();
        }
    }
}

メモリがダンプオブジェクトで過負荷になると、gcはfinalizeメソッドを呼び出します

実行してコンソールを確認します。ここでは、finalizeメソッドが頻繁に呼び出されていません。メモリが過負荷になると、finalizeメソッドが呼び出されます。

于 2016-02-01T11:37:05.910 に答える
0

Javaを使用すると、オブジェクトは、呼び出される可能性のあるfinalize()というメソッドを実装できます。

ガベージコレクターがオブジェクトを収集しようとすると、finalize()メソッドが呼び出されます。

ガベージコレクターが実行されない場合、メソッドは呼び出されません。

ガベージコレクターがオブジェクトの収集に失敗し て再度実行しようとすると、メソッドは2回目に呼び出されません。

実際には、実際のプロジェクトで使用する可能性はほとんどありません。

呼び出されない可能性があり、2回呼び出されることは絶対にないことに注意してください。finalize()メソッドは、0回または1回実行できます。

次のコードでは、ガベージコレクターを実行する必要がなくなる前にプログラムが終了するため、finalize()メソッドを実行しても出力は生成されません。

ソース

于 2016-07-25T09:07:50.960 に答える
0

finalize()ガベージコレクションの直前に呼び出されます。オブジェクトがスコープ外になった場合は呼び出されません。これは、いつ実行されるか、または実行されるかどうかさえわからないことを意味しますfinalize()

例:

ガベージコレクタが発生する前にプログラムが終了するfinalize()と、実行されません。したがって、プログラムが通常の操作で使用する手段としてではなく、他のリソースの適切な処理を保証するためのバックアップ手順として、または特殊用途のアプリケーションとして使用する必要があります。

于 2018-04-17T07:09:57.637 に答える
0

https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizersで指摘されているように、

実行時間はJava仮想マシン(JVM)に依存するため、ファイナライザーを実行する必要がある固定時間はありません。唯一の保証は、実行されるファイナライザーメソッドが、関連付けられたオブジェクトが到達不能になった後(ガベージコレクションの最初のサイクル中に検出された)、およびガベージコレクターが関連付けられたオブジェクトのストレージを再利用する前(ガベージコレクターの2番目のサイクル中)に実行されることです。 。オブジェクトが到達不能になった後、オブジェクトのファイナライザーの実行が任意の長い時間遅延する場合があります。その結果、オブジェクトのfinalize()メソッドでファイルハンドルを閉じるなどのタイムクリティカルな機能を呼び出すことには問題があります。

于 2019-11-30T11:46:28.260 に答える
-3

理解を深めるために、このプログラムを実行してみてください

public class FinalizeTest 
{       
    static {
        System.out.println(Runtime.getRuntime().freeMemory());
    }

    public void run() {
        System.out.println("run");
        System.out.println(Runtime.getRuntime().freeMemory());
    }

     protected void finalize() throws Throwable { 
         System.out.println("finalize");
         while(true)
             break;          
     }

     public static void main(String[] args) {
            for (int i = 0 ; i < 500000 ; i++ ) {
                    new FinalizeTest().run();
            }
     }
}
于 2017-01-17T13:21:30.653 に答える