.NET Framework のリソース開放基礎(2)

.NET Frameworkのリソース開放は非常に難解です。

今回は重要メソッドである以下の2つについて説明します。

・Dispose(リソースを開放できるメソッド、自動で呼ばれることはない
・Finalize(リソースを何時か開放するメソッド、自動で呼ばれる


実装時の注意点は以下のとおりです。

■ Dispose

  • Disposeは複数回呼ばれる可能性があるし、その場合に例外なしに呼び出せるよう実装しなくてはならない。
  • DisposeとFinalizeは殆ど似たような開放処理になる。しかし、アンマネージリソースの一部は、Disposeの実装とその呼び出しでしか開放できない
  • DisposeとFinalizeを両方実装した場合、Dispose内でGC.SuppressFinalizeをする(パフォーマンス上の問題)

■ Finalize

  • スレッドセーフに実装する必要はないし、複数回呼ばれることはない(GCがファイナライザを実行するスレッドは 1 つだけであることを保証している)。
  • Disposeが呼ばれなかったときの対策としてリソース開放を任せることができる場合がある。アンマネージリソースの大半はFinalizeの実装で開放できるため、予防線として開放処理を実装すべき(IDisposableなオブジェクトでDisposeを呼ばなくても、リークにならない場合があるのはFinalizeのおかげ)。
  • Finalizeは必ず呼び出されるわけではない。スレッドの停止等、特殊な条件で呼ばれない事がある。
    →つまり、OSに関連する重大なリソース(HWNDやHDC等)の開放はFinalizeに頼るべきではない。(これについては後述、CERにも関連)。
  • Finalizeを実装するとリソースの破棄に時間がかかる(Finalization Queue)

ここまではしっかり覚えておくべきです。

ついでに.NETのリソース利用におけるガイドラインを少し。

  • GCが管理できないリソースの開放は難解である。だから、アンマネージリソースにSafeHandleやCriticalHandleを使える場合は必ず使う。私たちが想像がつかないようなケースにも対応している。
  • 同様にGCが管理できないリソースを利用するのも難解である。GCHandle等のクラスはそれにも対応するので、自前でIntPtrなどを使うことは安全なリソース開放のためにもなるべく避けるべきである。

さて、メソッドやファイナライザによるリソースの破棄が完全に保障できない以上、サーバ系プログラムはどうすべきなのでしょうか?

Microsoftのだした1つの回答はCER(Constrained Execution Region)になります。
これについては次回。



[MSDN] CLR Inside Out Digging into IDisposable — MSDN Magazine, July 2007

Leave a Reply

Be the First to Comment!

Notify of
avatar
wpDiscuz