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

ガベージコレクタがあるからリソースの開放は不要、という説は間違いです。

ガベージコレクタが開放できるのは、.NET FrameworkのランタイムであるCLRが管理しているものですが、.NET Frameworkの内部ではCLRが管理しないリソースも呼び出せるからです。

その他、ガベージコレクタが苦手とするパターンも多々存在するわけで・・・


リソースを任意の時点で開放したい場合、一般的にはDispose関数を使います。

以下がDisposeを実装する事が強制されるパターンの1例です。

  • (クラス内部で)ネイティブリソースを使っている
  • マネージリソースのオブジェクト同士に依存関係がある(相互参照等も含む)
  • オブジェクトの状態を不定にしておくことができない
  • ファイナライザが別スレッドで動くことによる不都合を無視できない

1番目に該当するかの判断は難しいです。
.NET Frameworkのクラスライブラリがマネージヒープのリソース以外を使うか使わないかを外部から判断する方法がないからです。そのため、知らないクラスを使う場合、破棄をガベージコレクタに任せられるのかを判断するために、Dispose関数の説明を読んでおく必要があります。

2番目のようなクラスはそうありません。自作のクラスでは作らないようにしましょう。
参照カウンタについて調べたら、相互参照してるオブジェクト同士の破棄をガベージコレクタに任せられない理由が分かるはずです。弱い参照(Weak Reference)などを使っても、オブジェクトの開放順序を保障しない、現在のファイナライザに任せることができないケースも多々あるので、解決になりません。

3番目に該当するような例を1つあげてみます。
FileStreamクラスです。確かに、ファイナライザが呼ばれたらファイルは閉じられます。ただし、ファイナライザはいつ呼ばれるか分からないです。別のアプリケーションでファイルを読み書きした結果を使いたければ、ファイナライザを待たずに、自分でオブジェクトを破棄する必要があります。

4番目の理由は特殊です。
ガベージコレクタは別のスレッドで動きます。同一スレッドでしか呼び出せない関数を開放処理とする場合、明示的な破棄メソッドを作る事が強制されるのです。言い換えると、Disposeを実装して、それをファイナライザで呼び出せない(つまりガベージコレクタだけではどうにもならない)パターンです。例を挙げるとVistaで導入されたCancelIo系やRevertToSelfなど、同一スレッドでしか使えない関数がこれに当たります。別名のメソッドに開放処理を書く事もできますが、リソース開放メソッドの存在を見落とさせるだけでしょう。

なんかごちゃごちゃしてしまいましたが、次回はファイナライザとデストラクタについて書きます。
有名なパターン集(確定的ファイナライズとか)もまとめておこうと思います。

Leave a Reply

Be the First to Comment!

Notify of
avatar
wpDiscuz