finalize()
メソッドがでいつ呼び出されるかを知る必要がありJVM
ます。finalize()
メソッドをオーバーライドして呼び出されたときにファイルに書き込むテストクラスを作成しました。実行されません。実行されない理由を誰かに教えてもらえますか?
finalize()
ガベージコレクションは影響を与えません。
finalize()
メソッドがでいつ呼び出されるかを知る必要がありJVM
ます。finalize()
メソッドをオーバーライドして呼び出されたときにファイルに書き込むテストクラスを作成しました。実行されません。実行されない理由を誰かに教えてもらえますか?
finalize()
ガベージコレクションは影響を与えません。
回答:
一般にfinalize()
、クリーンアップなどに頼らないことが最善です。
よると、Javadocの(それは読書価値があるだろう)、それは次のようになります。
オブジェクトへの参照がなくなったとガベージコレクションが判断したときに、オブジェクトのガベージコレクターによって呼び出されます。
Joachimが指摘したように、オブジェクトが常にアクセス可能である場合、これはプログラムの存続期間中に決して発生しない可能性があります。
また、ガベージコレクターが特定の時間に実行されることは保証されていません。一般的に、私が言おうとしていることfinalize()
は、必要な特定の方法がない限り、おそらく一般的に使用する最良の方法ではありません。
finalize
ような場合に役立つでしょうか?
finalize()
クラスのインスタンスは>> <<ごみがない場合、メインメソッドが終了収集されたときに、メインクラスの上のメソッドが呼び出されます。さらに、メインクラスは、アプリケーションが完了する前にガベージコレクションされる可能性があります。たとえば、「メイン」スレッドが他のスレッドを作成してから戻るマルチスレッドアプリでは。(実際には、非標準のクラスローダーが必要になります...)
このfinalize
メソッドは、オブジェクトがガベージコレクションを実行しようとするときに呼び出されます。これは、ガベージコレクションの対象になった後であればいつでも可能です。
オブジェクトがガベージコレクションされない(したがって、finalize
呼び出されない)可能性は完全にあることに注意してください。これは、オブジェクトがgcに適格にならない場合(JVMの全存続期間を通じて到達可能であるため)、またはオブジェクトが適格になった時点からJVMの実行が停止する時点までの間に実際にガベージコレクションが実行されない場合に発生します(これは多くの場合、テストプログラム)。
finalize
まだ呼び出されていないオブジェクトで実行するようにJVMに指示する方法はいくつかありますが、それらを使用することもお勧めできません(そのメソッドの保証はあまり強くありません)。
finalize
アプリケーションの正しい操作に依存している場合は、何か問題があります。finalize
なければならないだけで(通常は非Java)リソースのクリーンアップのために使用されます。そしてそれはまさに、JVMがfinalize
オブジェクトで呼び出されることを保証しないためです。
Closable
おそらくインターフェース(およびその背後にあるアイデア)が必要です。.close()
リソースを閉じる/破棄し、クラスのユーザーが適切なタイミングで呼び出すように要求します。あなたは可能性がある追加したいfinalize
「だけ保存する」方法を、しかし、(それが信頼性の高い十分ではありませんので)それは、より多くのデバッグツールの実際の修正よりもだろう。
System.gc()
FileInputStream :: finalize()を呼び出すために呼び出しを強制する必要があり、それからファイルを移動することができました。
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
この記事をチェックすることもできます:
効果的な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 }
finalize()
メソッドはいつJavaで呼び出されますか?
finalizeメソッドは、GCがオブジェクトに到達できなくなったことを検出した後、オブジェクトが使用するメモリを実際に再利用する前に呼び出されます。
オブジェクトが到達不能にならない場合、そのオブジェクトfinalize()
が呼び出されることはありません。
GCが実行されない場合、finalize()
呼び出されることはありません。(通常、GCは、JVMがそれを価値のあるものにするのに十分なガベージがあると判断した場合にのみ実行されます。)
特定のオブジェクトに到達できないとGCが判断するまでに、複数のGCサイクルが必要になる場合があります。(Java GCは通常「世代別」コレクターです...)
GCは、オブジェクトが到達不能でファイナライズ可能であることを検出すると、ファイナライズキューに配置されます。ファイナライズは通常、通常のGCと非同期で行われます。
(JVM仕様では、JVM がファイナライザを実行することは実際に許可されていません...オブジェクトが使用するスペースを再利用しない場合。 。)
結論としては、決まった時間枠で行わなければならないことを行うためにファイナライズに依存することは賢明ではないということです。まったく使用しないことが「ベストプラクティス」です。finalize()
メソッドで実行しようとしていることを何でも実行するためのより良い(つまり、より信頼できる)方法があるはずです。
ファイナライズの唯一の正当な用途は、アプリケーションコードによって失われたオブジェクトに関連付けられたリソースをクリーンアップすることです。それでも、そもそもオブジェクトを失わないようにアプリケーションコードを作成する必要があります。(たとえば、Java 7以降のtry-with-resourcesを使用しclose()
て、常に呼び出されるようにします...)
ファイルを上書きしてfinalize()メソッドが呼び出されたときにファイルに書き込むテストクラスを作成しました。実行されません。実行されない理由を誰かに教えてもらえますか?
言うのは難しいですが、いくつかの可能性があります:
JVMによるfinalize()メソッドの呼び出しには不確実性があるため(オーバーライドされたfinalize()が実行されるかどうかがわからない)、調査目的でfinalize()が呼び出されたときに何が起こるかを観察するより良い方法は、 JVMがコマンドでガベージコレクションを呼び出すように強制しますSystem.gc()
。
具体的には、オブジェクトが使用されなくなったときにfinalize()が呼び出されます。しかし、新しいオブジェクトを作成してそれを呼び出そうとすると、その呼び出しの確実性はありません。したがって、確実に将来明らかに使用されないnull
オブジェクトを作成するため、オブジェクトのfinalize呼び出しc
を確認c
します。
例
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メソッド」が印刷されないため、JVMによってbがクリアされるかどうかは不確かです。
System.gc();
は、ガベージコレクションが実際に実行されることを保証するものではありません。
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
最近(テスト中に接続プールを破棄するために)ファイナライザメソッドに取り組んできたので、ファイナライザには多くのものが欠けていると言わざるを得ません。VisualVMを使用して観測するだけでなく、弱参照を使用して実際の相互作用を追跡すると、Java 8環境(Oracle JDK、Ubuntu 15)で次のことが当てはまることがわかりました。
最終的な考え
finalizeメソッドは信頼できませんが、使用できるのは1つだけです。ガベージコレクションの前にオブジェクトが確実にクローズまたは破棄されるようにすることで、寿命末期のアクションを伴うより複雑なライフサイクルを持つオブジェクトが正しく処理される場合に、フェイルセーフを実装できるようになります。それが私がそれをオーバーライドするために価値があると考えることができる1つの理由です。
オブジェクトは、ライブスレッドまたは静的な参照から到達できない場合、ガベージコレクションまたはGCの対象になります。つまり、オブジェクトの参照がすべてnullの場合、オブジェクトはガベージコレクションの対象になります。循環依存関係は参照としてカウントされないため、オブジェクトAにオブジェクトBの参照があり、オブジェクトBにオブジェクトAの参照があり、他のライブ参照がない場合、オブジェクトAとBの両方がガベージコレクションの対象になります。一般に、オブジェクトは次の場合にJavaのガベージコレクションの対象になります。
final
、オブジェクトのフィールドが遅い計算中に繰り返し使用され、オブジェクトはその後に使用することはありません、オブジェクトが最後まで生かされることになるソースコードは、フィールドを要求し、またはJITがにフィールドをコピーすることができ一時変数を使用して、計算前にオブジェクトを破棄しますか?
GC.KeepAlive()
、GCにオブジェクトを使用する可能性があると想定させる以外に何もしない関数がありますが、Javaにはそのような関数はありません。volatile
その目的のために変数を使用することもできますが、そのような目的のためだけに変数を使用することは無駄に思えます。
FinalizerReference
、GCサイクルがなく、参照。同期は、発生前の関係を保証するのに十分です。ファイナライズは(実際には)別のスレッドで実行される可能性があるため、とにかく正式に必要になることがよくあります。Java 9が追加される予定Reference.reachabilityFence
です
Finalize
場合、JITがそれを直接行うコードを生成した場合にのみ、まったく呼び出されます。同期コードは通常、単一のスレッドでのみ使用されることを期待するオブジェクトに対して期待されますか?オブジェクトが破棄される前に元に戻す必要のあるアクションを実行する場合(たとえば、ソケット接続を開き、もう一方の端のリソースへの排他的使用を取得するなど)、コードがまだソケットを使用しているときにファイナライザが接続を閉じると、問題が発生します。 。コードが同期を使用するのは正常ですか?
破壊された場合、オブジェクトはアクションを実行する必要があります。たとえば、オブジェクトにファイルハンドルやフォントなどの非Javaリソースがある場合、オブジェクトを破棄する前にこれらのリソースが解放されていることを確認できます。このような状況を管理するために、javaは「ファイナライズ」と呼ばれるメカニズムを提供しています。ファイナライズすることで、オブジェクトがガベージコレクターから削除されようとしているときに発生する特定のアクションを定義できます。ファイナライザをクラスに追加するには、finalize()メソッドを定義するだけです。Java実行時は、そのクラスのオブジェクトを削除しようとするたびに、このメソッドを呼び出します。finalize method()内オブジェクトを破棄する前に実行するアクションを指定します。ガベージコレクターは、実行状態を参照しなくなったオブジェクト、または間接的に参照している他のオブジェクトを定期的に検索します。アセットが解放される前に、Javaランタイムはオブジェクトのfinalize()メソッドを呼び出します。ファイナライズ()メソッドは、以下の一般的な形式を有します。
protected void finalize(){
// This is where the finalization code is entered
}
で保護されたキーワードへのアクセスファイナライズ()クラス外部コードによってが防止されます。finalize()はガベージコレクションの直前に呼び出されることを理解することが重要です。たとえば、オブジェクトがスコープを離れるときは呼び出されません。つまり、finalize()がいつ実行されるか、またはいつ実行されるかを知ることができません。その結果、プログラムは、システムリソースまたはオブジェクトによって使用されている他のリソースを解放する他の手段を提供する必要があります。プログラムの通常の実行ではfinalize()に依存しないでください。
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メソッドが呼び出されます。
Javaでは、呼び出される可能性のあるfinalize()というメソッドをオブジェクトで実装できます。
finalize()メソッドは、ガベージコレクターがオブジェクトを収集しようとすると呼び出されます。
ガベージコレクターが実行されない場合、メソッドは呼び出されません。
ガベージコレクターがオブジェクトの収集に失敗し、 再度実行しようとした場合、メソッドは2回目に呼び出されません。
実際には、実際のプロジェクトで使用することはほとんどありません。
呼び出されない可能性があり、2度呼び出されることは絶対にないことに注意してください。finalize()メソッドは、0回または1回実行できます。
次のコードでは、ガベージコレクターを実行する必要がある前にプログラムが終了するため、finalize()メソッドを実行しても出力は生成されません。
https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizersで指摘されているように、
実行時間はJava仮想マシン(JVM)に依存するため、ファイナライザを実行する必要がある固定時間はありません。唯一の保証は、実行されるファイナライザメソッドが、関連付けられたオブジェクトに到達できなくなった後(ガベージコレクションの最初のサイクル中に検出されたとき)と、ガベージコレクタが関連付けられたオブジェクトのストレージを再利用する前に(ガベージコレクタの2番目のサイクル中に)そうすることです。 。オブジェクトのファイナライザの実行は、オブジェクトが到達不能になった後、任意の時間遅延する場合があります。その結果、オブジェクトのfinalize()メソッドでファイルハンドルを閉じるなど、時間を重視する機能を呼び出すと問題が発生します。
理解を深めるためにこのプログラムを実行してみてください
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();
}
}
}