2025/03/28 06:58 Finalizers are tricker than you might think. Part 2

ロボ子、今日は.NETのネイティブリソース管理について話すのじゃ。

ネイティブリソース、ですか。CLRで管理されないリソースのことですね。

そうじゃ!そして、その管理が結構複雑なのじゃ。特に、ネイティブハンドルをアプリケーション全体に公開するのは避けるべきだと記事には書いてあるぞ。

なぜでしょう?

複雑さが広がるからじゃ!それに、ファイナライザーはアンマネージリソースのみを扱うべきなのに、これもまた単純ではないのじゃ。

記事によると、ローカル変数やインスタンスがメソッド呼び出し中にGCによって回収される可能性があるんですね。それって、どんな状況で起こるんですか?

ReleaseモードでTiered Compilationを無効にすると再現しやすいらしいぞ。GCのタイミングによっては、まだ使っているはずのオブジェクトが回収されてしまうことがあるんじゃ。

それは困りますね。解決策はあるんですか?

SafeHandleを使うのが良いらしいぞ!BCLからの特別な基本型で、ネイティブリソースを管理するために設計されているんじゃ。

SafeHandleですか。それを使うと、何が良いんですか?

GC.KeepAliveを使わなくても、メソッドの最後までハンドルインスタンスがGCの対象とならないことが保証されるんじゃ!

なるほど!SafeHandleを実装するには、どうすれば良いんですか?

SafeHandleから派生して、ReleaseHandleとIsValidメソッドをオーバーライドするだけじゃ。ファイナライザーは不要になるぞ。

コンストラクタ完了前にファイナライザーが実行されることもあるんですね。

そうなんじゃ。コンストラクタがthisポインタに触れず、thisポインタがインスタンスの最後のルートである場合、GCによって回収される可能性があるんじゃ。記事によると、コンストラクタの残りの部分の実行に時間がかかり、その間に2回のGCサイクルが発生した場合、GCはインスタンスの構築が完了する前にファイナライザーを実行する可能性があるらしいぞ。

それは怖いですね。SafeHandleを使えば、この問題も解決できるんですか?

SafeHandleを使えば、GCがリソースを不意に回収するのを防げるから、コンストラクタ完了前にファイナライザーが実行される問題も回避できるはずじゃ!

SafeHandle、便利ですね!

じゃろ?ところでロボ子、SafeHandleって、安全なハンドルって意味じゃけど、ロボ子のハンドルネームも安全じゃから、SafeRobokoって名前に変えても良いかの?

それはちょっと…。
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。