.NETでは、オブジェクトが部分的に構築されている場合でもファイナライザが実行されることを理解しています(コンストラクタから例外がスローされた場合など)。.NETでは、オブジェクトのコンストラクタが実行されなかった場合でもファイナライザを実行できますか?
背景
私は、以下の効果行い、いくつかのC++/CLIのコードを持っている(私はこれはC++/CLIは固有であるとは思わないが、これは私が準備に持っている状況です):
try {
ClassA ^objA = FunctionThatReturnsAClassA();
ClassB ^objB = gcnew ClassB(objA); // ClassB is written in C# in a referenced project
...
}
catch (...) {...}
FunctionThatReturnsAClassA()から例外がスローされ、GCがトリガーされた場合(このコードを再度実行することによって確実にトリガーされるように見えますが、しばらく待つこともできます) ClassBのファイナライザが呼び出されます。
今、トレース出力を介して、私はClassBのコンストラクタが実行されていないことを確認できます(これは当然のことです)。したがって、何らかの形で、objBは、コンストラクタを呼び出すための前提条件が満たされる前に(つまり、FunctionThatReturnsAClassA()から結果を収集する前に)明らかに割り当てられ、ファイナライザリストに追加されました。
これは、デバッガの外部で実行される最適化されたリリースビルドでのみ発生します。たとえば、2つのステートメントの間に別のメソッド呼び出しを挿入するなど、ファイナライザが実行されないような小さな変更が多数あります。つまり、 "gcnew ClassB"を別の関数に移動してオブジェクト。
gcnewステートメントの割り当て部分が並べ替えられて前のステートメントより前に実行されているようですが、この並べ替えは生成されたMSILコードには反映されません(これは別のC++/CLIコードのgenのバグ)。さらに、生成されたMSILコードを「バグ」状態と「固定」状態のいずれかと比較すると、予期せぬ構造上の変化は見られません。
私はデバッガでも生成されたx86コードを見てきましたが、これまで見た目は変わっていませんが、深く解析していないので、デバッガでこの動作を再現できません私はデバッガから取得したコードが奇妙な動作を示すコードと同じであることを100%確信していません。
これはMSIL-> x86コードである可能性があります。または、プロセッサの命令の並べ替えを行うことができます(以前のようですが、ビヘイビアが発生したときにメモリ内の正確なコードを取得することによって - これは私の次のステップです)。
質問
だから、.NETでオブジェクトの割り当てのために離婚するために、そのオブジェクトのコンストラクタ呼び出しとは別に並べ替え有効(より良い用語の欠如のために)ですか?
オブジェクトが呼び出して、コンストラクタのいずれかを呼び出すことなく割り当てられるすることが可能です[ 'FormatterServices.GetUninitializedObject()'](HTTPS:// MSDN
これは現在、JIT最適化のバグであることが確認されましたMicrosoft.com/ja-jp/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspx)。 'BinaryFormatter'と' DataContractSerializer'はこのようにしてオブジェクトを構築します。後で、オブジェクトにファイナライザがある場合は、ファイナライザが完成します。しかし、私はそれがあなたが見ているものだとは思わない、それは? – dbc
これは正確に私が見ているものではありませんが、フレームワークがこのようにオブジェクトを作成できることを強調しています。少なくとも理論的には、割り当てと構築の間に何かが中断する可能性があります。しかし、標準のnew/gcnewステートメントの一部として実行されたときに、2つのステージが分割されることが合法であるかどうかは、答えません。 – rationull
Jitterオプティマイザのバグが発生する可能性があります。しかしこれではなく、オブジェクトの割り当て(ファイナライザの実行を取得する)とコンストラクタ呼び出しは、CLRヘルパ関数への単一呼び出しです。 1回の呼び出しで再注文問題が発生することはありません。文書化されたCLRのバージョン番号が記載された良好なレプロを必要とし、先に進むにはMicrosoftサポートで電話を受ける必要があります。 –