問題タブ [finalization]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c# - オブジェクトがまだ使用されている間にファイナライザーが起動されました
概要: C#/.NET はガベージ コレクションの対象になるはずです。C# には、リソースをクリーンアップするために使用されるデストラクタがあります。オブジェクト A が、その変数メンバーの 1 つを複製しようとしたのと同じ行でガベージ コレクションされるとどうなりますか? どうやら、マルチプロセッサでは、ガベージコレクタが勝つことがあります...
問題
今日、C# のトレーニング セッションで、先生は、マルチプロセッサで実行した場合にのみバグを含むコードをいくつか見せてくれました。
要約すると、呼び出されたメソッドから戻る前に C# クラス オブジェクトのファイナライザーを呼び出して、コンパイラーまたは JIT が失敗することがあります。
Visual C++ 2005 ドキュメントに記載されている完全なコードは、非常に大きな質問を避けるために「回答」として投稿されますが、重要なものは以下のとおりです。
次のクラスには、内部配列の複製コピーを返す「ハッシュ」プロパティがあります。この構築では、配列の最初の項目の値は 2 です。デストラクタでは、その値はゼロに設定されます。
ポイントは次のとおりです。「例」の「ハッシュ」プロパティを取得しようとすると、オブジェクトが使用されているため (そのため、使用されていないため、最初の項目がまだ 2 である配列のクリーンなコピーが取得されます)。ガベージ コレクション/ファイナライズ済み):
しかし、これほど単純なことはありません... このクラスを使用するコードはスレッド内で実行されます。もちろん、テストのために、アプリは高度にマルチスレッド化されています。
DoWork 静的メソッドは、問題が発生するコードです。
DoWork の 1,000,000 回の実行ごとに、明らかに、ガベージ コレクターはその魔法を実行し、関数の remaning コードで参照されなくなったため、"ex" を再利用しようとします。今回は、"Hash" よりも高速です。メソッドを取得します。したがって、最終的に得られるのは、正しいバイト配列 (最初の項目が 2 の場合) ではなく、ゼロで埋められたバイト配列のクローンです。
私の推測では、コードのインライン化があり、DoWork 関数で [1] とマークされた行が次のように置き換えられます。
Hash2 が次のようにコード化された単純なアクセサであると仮定した場合:
問題は、これは C#/.NET でそのように動作するはずなのか、それとも JIT のコンパイラのバグと見なすことができるのかということです。
編集
説明については、Chris Brumme と Chris Lyons のブログを参照してください。
http://blogs.msdn.com/cbrumme/archive/2003/04/19/51365.aspx
http://blogs.msdn.com/clyon/archive/2004/09/21/232445.aspx
皆さんの回答は面白かったのですが、どれも良いとは言えませんでした。だから私はあなたに+1を与えました...
ごめん
:-)
編集 2
同じ条件 (複数の同じ実行可能ファイルを同時に実行する、リリース モードなど) で同じコードを使用したにもかかわらず、Linux/Ubuntu/Mono で問題を再現できませんでした。
c# - C#-「デストラクタは継承されない」とは実際にはどういう意味ですか?
C#言語仕様3.0のセクション10.13、デストラクタは次のように述べています。
デストラクタは継承されません。したがって、クラスには、そのクラスで宣言できるデストラクタ以外のデストラクタはありません。
C#プログラミングガイドのデストラクタセクションには、継承階層内のデストラクタがどのように呼び出されるかを示す例が含まれています。これには、次のステートメントが含まれます。
...クラスのデストラクタは自動的に呼び出され、最も派生したものから最も派生しなかったものへと順番に呼び出されます。
デストラクタを定義する基本クラス、基本クラスから継承し、デストラクタを定義しない派生クラスなど、さまざまな実用的な例でこれを調査しました。派生クラスのインスタンスを作成し、インスタンスへのすべての参照をスコープ外に出してからガベージコレクションを強制すると、派生クラスのインスタンスがファイナライズされたときに基本クラスで定義されたデストラクタが呼び出されることがわかります。
私の質問は、「デストラクタは継承されない」とは実際にはどういう意味ですか。デストラクタを明示的に呼び出すことはできませんが、継承チェーン内のデストラクタは自動的に呼び出され、派生クラスがデストラクタを定義していなくても基本クラスのデストラクタが呼び出されます。 ?
ファイナライズがC#言語/コンパイラではなくガベージコレクタによって実装されるという、いくつかの微妙な意味上の違いに関連していますか?
編集1:
C#言語仕様では、「インスタンスコンストラクターは継承されない」と規定されていますが、コンストラクターに関連する動作は記述子とは大幅に異なり、以下の例に示すように、「継承されない」用語でIMOに適合します。
次の例に示すように、デストラクタに関連する動作はこれとは大きく異なります。次の例では、基本クラスにのみ記述子を追加することで、前のコンストラクタの例を拡張しています。
上記の例は、派生クラスがデストラクタを明示的に定義していなくても、派生クラスのインスタンスがファイナライズされたときに基本クラスコンストラクタが呼び出されることを示しています。
私の言いたいことは、これが何が起こっているのかを理解または理解していない多くの人々に出会ったということです。この理由の重要な部分は、「デストラクタは継承されない」というステートメントです。
編集2:
C#言語仕様には、次のことも記載されており、内部実装のコード例が示されています。
デストラクタは、System.Objectの仮想メソッドFinalizeをオーバーライドすることによって実装されます。C#プログラムでは、このメソッドをオーバーライドしたり、直接呼び出したり(またはオーバーライドしたり)することはできません。
ボンネット内の実装は、実際には、前述のように継承に基づいているため、私の質問は有効であり、これまでに受け取った応答のいずれも、質問に適切に対処していないと思います-何「デストラクタは継承されない」とは、実際にはどういう意味ですか?
delphi - 単位での Delphi とファイナライズ
unitA と unitB の 2 つのユニットがあります。クラス TFoo は unitB で宣言されています。
unitA のファイナライズで B.Free を呼び出すことは常に安全ですか?
unitA と unitB が dpr にある順序にどのように依存しますか?
unitA ファイナライズが実行されたときに unitB が存在することを確認できますか?
java - Javaでのファイナライズの目的は何ですか?
ファイナライズについての私の理解はこれです:
オブジェクトが占有するメモリをクリーンアップまたは再利用するために、ガベージコレクタが機能します。(自動的に呼び出されますか?)
次に、ガベージコレクターはオブジェクトを逆参照します。ガベージコレクタがオブジェクトにアクセスする方法がない場合があります。次に、finalizeが呼び出されて最終クリーンアップ処理が実行され、その後ガベージコレクターが呼び出されます。
これはファイナライズの正確な説明ですか?
delphi - ランタイムパッケージでコンパイルされたアプリケーションのユニットファイナライズ順序?
SysUtilsユニットのファイナライズ後にコードを実行する必要があります。
コードを別のユニットに配置し、最初に次のようにdpr-fileのuses句に含めました。
MyUnitは次のようになります。
MyUnitには用途がないことに注意してください。
これは通常のWindowsexeであり、コンソールはなく、フォームがなく、デフォルトのランタイムパッケージでコンパイルされています。MyUnitはパッケージの一部ではありません(ただし、パッケージからも使用しようとしました)。
MyUnitのファイナライズセクションは、SysUtilsのファイナライズセクションの後に実行されることを期待しています。これはDelphiの助けが私に教えてくれることです。
ただし、これが常に当てはまるとは限りません。
私は2つのテストアプリを持っていますが、テストルーチン/dprファイルとユニットのコードによって少し異なります。ただし、すべての場合でMyUnitが最初にリストされます。
1つのアプリケーションが期待どおりに実行されます:Halt0-> FinalizeUnits-> ... other units...->SysUtilsのファイナライズ->MyUnitのファイナライズ->...other units .. ..
しかし、2番目はそうではありません。MyUnitのファイナライズは、 SysUtilsのファイナライズの前に呼び出されます。実際のコールチェーンは次のようになります。Halt0->FinalizeUnits->...その他のユニット...->SysUtilsのファイナライズ(スキップ)->MyUnitのファイナライズ->...その他のユニット...->SysUtilsのファイナライズ(実行済み)
どちらのプロジェクトも非常によく似た設定になっています。私はそれらの違いを取り除く/最小化するために多くのことを試みましたが、それでもこの振る舞いの理由はわかりません。
私はこれをデバッグしようとしましたが、次のことがわかりました。すべてのユニットに何らかの参照カウントがあるようです。また、InitTableには同じユニットへの複数の参照が含まれているようです。SysUtilsのファイナライズセクションが最初に呼び出されると、参照カウンターが変更され、何も実行されません。次に、MyUnitのファイナライズが実行されます。次に、SysUtilsが再度呼び出されますが、今回はref-countがゼロに達し、ファイナライズセクションが実行されます。
誰でもこの問題に光を当てることができますか?私は何かが足りないのですか?
vb.net - VBのメモリリーク
VBのメモリ管理に関して、理解できない興味深い問題が1つあります。誰かがこれを手伝ってくれるなら、してください。
1つのイベントを含む単純なクラスがあります。このクラスの5000個のインスタンスを作成して破棄し、テストを実行する前に、プロセスのメモリ使用量を読み取ります。最後に、GCを強制してメモリを再度チェックします。気付いたのは、メモリが常に増えていることです。C#で同じサンプルを実行しましたが、この問題は発生しませんでした。これが有線ポイントです。クラスからイベント宣言を省略すると、メモリは期待どおりにクリーンアップされます。誰もがその理由を知っていますか、そしてこのクラスを完成させる正しい方法は何ですか。
サンプルコードは次のとおりです。
およびテストクラス:
そして、数回実行した後のプリントアウト:
wpf - WPFアプリケーションの初期化とファイナライズ
ICE(インターネット通信エンジン)ミドルウェアを使用するWPFクライアントアプリケーションを作成する準備をしています。ICEには、適切な初期化とファイナライズが必要です。すべての例は、通常のコンソールアプリケーションでこれを実現する方法を示しています。これは、try-finallyをブロックして、いくつかの処理を実行するだけでよいため、簡単です。
WPFはどうですか?一部のコードが問題なしと呼ばれることをどのように確認できますか?アプリを完成させるにはどうなりますか?
java-native-interface - JNI 非 Java クラス メンバー
C インターフェイスを持つサードパーティ ライブラリに対して Java ラッパーを作成したいと考えています。このライブラリは、本質的に C++ オブジェクトである複雑な Context エンティティで動作します (C++ はそのライブラリで内部的に使用されますが、API は純粋な C です)。このエンティティを Java からアクセス可能なクラスにラップするのが自然です。そのためには、Context へのポインターをどこかに格納する必要があります。
これを行うには、次の 2 つのオプションがあります。
- Java側で新しいメンバーを宣言し(たとえば、長い場合)、JNIメソッド実装内でポインター型に変換します
- JNIヘッダーで新しいメンバーを宣言します(Javaがjavahによって生成された構造のサイズに依存している場合、これは違法かもしれません)
JNI のすべてのチュートリアルは単純すぎて、複雑なエンティティを Java クラスでラップする方法についてのヒントを得ることができません。より詳細なドキュメントへのリンクを歓迎します。
また、Context 破壊関数 (内部の C++ デストラクタ) を呼び出すのが適切な場所を知りたい Java は finalize メソッドを好まないため、そのために Java finalize を使用したくありません。また、破壊手順を定義する方法があると思います。ネイティブ側。
java - ファイナライズは後のJVMではまだ悪いニュースだと確信しています-代替手段はありますか?
呼び出し元が到達できなくなったときにPOJOへの更新を保存できるORMスタイルのシステムを実装したいと思います。
参照クラスはそれを実行できると思いましたが、オブジェクトがクリアされた後にのみ参照をキューに入れるようです(収集できるようになったときだと思っていました)。したがって、キューに入れると、.get()メソッドは常に返されます。ヌル。
ファイナライザーを使用することはできましたが、前回それらが疑わしいことを確認しました(すぐに実行される、またはまったく実行されるとは限りません)-ファイナライザーとrunShutdownHook()の組み合わせは機能すると思いますが、それはかなり沼沢地になりつつあります。
義務的な「呼び出し元が完了したら.save()を呼び出すだけ」以外に、私が考えていない別のパスはありますか?
java - 定義: ファイナライズされていないオブジェクトとファイナライズ可能なオブジェクト
Java の弱参照を理解するために、Java 言語仕様を調べる必要がありました。セクション 12.6 の次の部分は、私を困惑させます。
ファイナライズされていないオブジェクトでは、ファイナライザーが自動的に呼び出されたことはありません。ファイナライズされたオブジェクトのファイナライザーが自動的に呼び出されました。ファイナライズ可能なオブジェクトでは、ファイナライザーが自動的に呼び出されることはありませんが、Java 仮想マシンは最終的にそのファイナライザーを自動的に呼び出す可能性があります。
では、ファイナライズされていないオブジェクトとファイナライズ可能なオブジェクトの正式な違いは何ですか? 引用から、ファイナライズされていないオブジェクトとファイナライズ可能なオブジェクトが異なる場合、ファイナライズされていないオブジェクトの場合、JVM が最終的にそのファイナライザーを呼び出す可能性があるというのは事実ではないようです。少し混乱するか、まだ勉強する英語のセマンティクスがいくつかあります;)
Java 仕様のセクションへのリンク:ファイナライズの実装