ホームページ  >  記事  >  Java  >  Java オブジェクトの破棄およびファイナライズ メソッドの使用方法

Java オブジェクトの破棄およびファイナライズ メソッドの使用方法

王林
王林転載
2023-04-15 09:58:05737ブラウズ

オブジェクトの破棄

C では、リソースを解放し、オブジェクト自体を破棄するためにデストラクター メソッドが使用されます。

Java では GC の存在により、手動でメモリを再利用する必要がなくなり、作業負荷が大幅に軽減され、プログラムのセキュリティが向上します。ただし、Java には C のデストラクターに似た機能があります。

finalize メソッド

クラスが GC によってリサイクルされるときにいくつかの操作を実行するには、このメソッドをオーバーロードします。

次は、finalize を実装するクラスの例です。

Aoo クラスには int と String プロパティがあり、toString をオーバーロードして、構築時にオブジェクトとその作成時間を出力し、ファイナライズ時にオブジェクトと呼び出し時間を出力します。

Aoo クラス

public class Aoo {
       private int id;
       private String name;

       public Aoo(){
              this(0, null);
       }

       public Aoo(int id, String name){
              this.id = id;
              this.name = name;
              System.out.println(this.toString() + " now create:" + System.currentTimeMillis());
       }
        /*
        * 省略get/set/toString
        */
       protected void finalize() throws Throwable{
              super.finalize();
              System.out.println(this.toString() + "now finalize:" + System.currentTimeMillis());
       }
}

まず、簡単なテスト

メイン メソッド

public class FinalizeTest {
       public static void main(String[] args) throws Exception {
              Aoo a = new Aoo(1, "a");
              a = null;
              System.gc()
              Thread.sleep(2000);
              System.exit(0);
       }
}

結果を出力します:

id:1 name:a now create:1497547723036
id:1 name:anow Finalize:1497547724059

オブジェクトの GC リサイクル

メモリをクリーンアップするためにここで GC が手動で呼び出されます。System.gc(); をコメントアウトすると、出力結果は次のようになります:

id:1 name:a now create: 1497547846923

つまり、GC を特に呼び出さなければ、finalize メソッドはまったく呼び出されません。これは、オブジェクトがまったくアクティブにリサイクルされないことを意味します。

想像に反して、GC は遅延的に動作します。つまり、メモリに場所がない場合、GC はオブジェクトを積極的にリサイクルしません。このアイデアを検証するために、スレッドを作成しました。メモリを継続的に消費し、積極的に GC を呼び出さないために使用されます。

ThreadA クラス

public class ThreadA implements Runnable{
       public void run() {
              List<Integer> list = new ArrayList<Integer>();
              int i = 0;
              while(true){
                     list.add(i);
                     i++;
              }
       }
}

メイン メソッド

public class FinalizeTest {
       public static void main(String[] args) throws Exception {
              Aoo a = new Aoo(1, "a");
              a = null;
              ThreadA ta = new ThreadA();
              Thread t = new Thread(ta);
              t.start();
              Thread.sleep(2000);
              System.exit(0);
       }
}

出力結果:

id: 1 name:a now create:1497548135268
id:1 name:anow Finalize:1497548135386

今回は GC は手動で呼び出されませんでしたが、finalize メソッドは引き続き実行されました。 if GC は、メモリが消費され、GC がメモリをクリーンアップする必要がある場合にのみ実行されます。

このようなファイナライズ メソッドは確かに信頼性が低く、特定の操作を完了することはおろか、呼び出せるかどうかさえわかりません。ストリームを閉じてリソースを回復する必要がある場合は、メソッドを呼び出すことをお勧めします。手動で、またはリソースは最終ブロックで均一に解放されます。

finalize メソッドでは、GC によるリサイクルを避けるために参照を自分自身に再割り当てする必要がありますか?

GC のリサイクルを防ぐために、finalize メソッドで再参照してみてください。

変更された Aoo は次のとおりです。

public class Aoo {
       public static Aoo SAVE = null;
       private int id;
       private String name;

       public Aoo(){
              this(0, null);
       }

       public Aoo(int id, String name){
              this.id = id;
              this.name = name;
              System.out.println(this.toString() + " now create:" + System.currentTimeMillis());
       }  
       /*
        * 省略get/set/toString
        */
       protected void finalize() throws Throwable{
              super.finalize();
              System.out.println(this.toString() + "now finalize:" + System.currentTimeMillis());
              SAVE = this;
       }
}

main メソッド

public class FinalizeTest {
       public static void main(String[] args) throws Exception {
              Aoo.SAVE = new Aoo(1, "a");
              Aoo.SAVE = null;
              System.gc();
              Thread.sleep(500);
              System.out.println(Aoo.SAVE == null? "a is dead" : "a is alive" );              
              System.exit(0);             
       }
}

印刷結果:

id:1 name:a now create:1497551409195
id:1 name:anow Finalize:1497551409201
a is生きています

ここで、Aoo.SAVE オブジェクトが確かに「復活」していることがわかりますが、この操作には制限があり、同じ操作を繰り返した場合、オブジェクトは再び「復活」することはありません。

メインメソッド

public class FinalizeTest {
       public static void main(String[] args) throws Exception {
              Aoo.SAVE = new Aoo(1, "a");
              Aoo.SAVE = null;
              System.gc();
              Thread.sleep(500);
              System.out.println(Aoo.SAVE == null? "a is dead" : "a is alive" );

              Aoo.SAVE = null;
              System.gc();
              Thread.sleep(500);
              System.out.println(Aoo.SAVE == null? "a is dead" : "a is alive" );

              System.exit(0);          
       }
}

印刷結果:

id:1 name:a now create:1497551587715
id:1 name :anow Finalize:1497551587721
a は生きています
a は死んでいます

ここで、2 つの操作は同じであり、finalize メソッドはシステムによって 1 回だけ呼び出されることに注意してください。

finalze メソッドで無限ループが発生するとどうなりますか?

Aoo クラス

public class Aoo {
       private int id;
       private String name;

       public Aoo(){
              this(0, null);
       }

       public Aoo(int id, String name){
              this.id = id;
              this.name = name;
              System.out.println(this.toString() + " now create:" + System.currentTimeMillis());
       }
       /*
        * 省略get/set/toString
        */
       protected void finalize() throws Throwable{
              super.finalize();
              while(true){
                     System.out.println(this.toString() + "now finalize:" + System.currentTimeMillis());
                     Thread.sleep(100);
              }
       }
}

メイン メソッド

public class FinalizeTest {
       public static void main(String[] args) throws Exception {
              Aoo a1 = new Aoo(1 , "a1");
              Aoo a2 = new Aoo(2 , "a2");
              a1 = null;
              a2 = null;
              ThreadA ta = new ThreadA();
              Thread t = new Thread(ta);
              t.start();
              Thread.sleep(5000);

              System.exit(0);
       }
}

出力結果:

id: 1 名前:a1 作成中:1497552024252
id:2 名前:a2 作成中:1497552024252
id:1 名前:a1 作成中:1497552024373
id:1 名前:a1 作成中:1497552024503
id: 1 name:a1now Finalize:1497552026848
id:1 name:a1now Finalize:1497552028960
id:1 name:a1now Finalize:1497552032363

結果はランダムであり、場合によっては実行されます。 a1 は a2 によって実行される場合があります。

この結果は 2 つの点を示しています:

1. Finalze メソッドのスレッド優先度は非常に低く、時間間隔は非常に不確実で、100 ミリ秒を大幅に超えています。 。

2. この無限ループにより、他のオブジェクトの Finalize メソッドの実行が失敗します。

オブジェクト作成時にこのような無限ループが発生すると、オブジェクトを破棄できなくなり、メモリオーバーフローが発生するのでしょうか?

大量の Aoo オブジェクトを作成し、GC が自らメモリを再利用するのを待ちます。

finalize メソッドの呼び出しを視覚的に確認するために、Aoo オブジェクトの初期化時の出力コードを削除します。

メイン メソッド

public class FinalizeTest {
       public static void main(String[] args) throws Exception {
              int i = 1;
              while(true){
                     Aoo a = new Aoo(i , "a" + i);
                     i++;
              }
       }
}

プログラムを約 2 分間実行し、手動で終了して出力を確認します

1497554225913
id:269614 名前:a269614現在最終化:1497554226151
id:269614 名前:a269614現在最終化:1497554227635
id:269614 名前:a269614現在最終化:1497554227735
id: 269614 名前:a269614現在ファイナライズ:1497554227836
id:269614 名前:a269614現在ファイナライズ:1497554229586
id:269614 名前:a269614現在ファイナライズ:1497554229686
id:269614 名前:a269614現在ファイナライズ:149755 4229951
id:269614 名前:a269614今ファイナライズ:1497554230051
id:269614 名前:a269614今ファイナライズ:1497554230152
id:269614 名前:a269614今ファイナライズ:1497554233699
id:269614 名前:a269614今ファイナライズ:1497554233800
id: 269614 名前:a269614今最終決定: 1497554233900
id:269614 名前:a269614現在最終化:1497554234308
id:269614 名前:a269614現在最終化:1497554234408
id:269614 名前:a269614現在最終化:1497554234508
id:26 9614 名前:a269614現在完了:1497554235053
id:269614 名前:a269614現在最終化:1497554235153
id:269614 名前:a269614現在最終化:1497554235253
id:269614 名前:a269614現在最終化:1497554235823
id:269614 名前:a269614これで完了:1497554235923
id:269614 名前:a269614現在最終化:1497554236023
id:269614 名前:a269614現在最終化:1497554240324
id:269614 名前:a269614現在最終化:1497554240424
id:269614 名前:a269614現在最終化ize:1497554240525
id: 269614 名前:a269614現在ファイナライズ:1497554241146
id:269614 名前:a269614現在ファイナライズ:1497554241247
id:269614 名前:a269614現在ファイナライズ:1497554241347
id:269614 名前:a269614今ファイナライズ:1497554241448
id:269614 名前:a269614現在ファイナライズ:1497554242020
id:269614 名前:a269614現在ファイナライズ:1497554242120
id:269614 名前:a269614現在ファイナライズ:1497554242220
id:269614 名前:a269614現在ファイナライズ:149755 4242321
id:269614 名前:a269614今ファイナライズ:1497554242421
id:269614 名前:a269614今ファイナライズ:1497554242521
id:269614 名前:a269614今ファイナライズ:1497554248367
id:269614 名前:a269614今ファイナライズ:1497554248467
id: 269614 名前:a269614今最終決定: 1497554248567
id:269614 名前:a269614現在最終化:1497554248667
id:269614 名前:a269614現在最終化:1497554249534
id:269614 名前:a269614現在最終化:1497554249634
id:26 9614 名前:a269614現在完了:1497554249734
id:269614 名前:a269614現在最終化:1497554249835
id:269614 名前:a269614現在最終化:1497554255954
id:269614 名前:a269614現在最終化:1497554256055
id:269614 名前:a269614これで完了:1497554256155
id:269614 名前:a269614現在最終化:1497554256255
id:269614 名前:a269614現在最終化:1497554256356
id:269614 名前:a269614現在最終化:1497554257285
id:269614 名前:a269614現在最終化ize:1497554257386
id: 269614 名前:a269614現在終了:1497554257486
id:269614 名前:a269614現在終了:1497554257586
id:269614 名前:a269614現在終了:1497554257686
id:269614 名前:a269614現在終了:1497554268652
id:269614 名前:a269614現在ファイナライズ:1497554268753
id:269614 名前:a269614現在ファイナライズ:1497554268853
id:269614 名前:a269614現在ファイナライズ:1497554268953
id:269614 名前:a269614現在ファイナライズ:149755 4269054
id:269614 名前:a269614今ファイナライズ:1497554269154
id:269614 名前:a269614今ファイナライズ:1497554277474
id:269614 名前:a269614今ファイナライズ:1497554292852
id:269614 名前:a269614今ファイナライズ:1497554301062

2 つの状況が発生する可能性があります:

1. 1 つのオブジェクトの終了メソッドのみが実行されました。つまり、この死循環の終了メソッドは、他のオブジェクトの終了メソッドの実行を阻止します。

2. プログラムが非常に短時間で実行された後、ファイナライズ メソッドが実行され始めますが、内部メモリの消費が継続的に増加するにつれて、ファイナライズ メソッドが実行される回数も増加します。

以上がJava オブジェクトの破棄およびファイナライズ メソッドの使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。