ファイナライザとIDisposableインタフェース(C#)

ファイナライザとかIDisposableインタフェースを使ったメモリ管理について、

フローチャート書いたら理解が深まったのでメモを残しておきます。
(参考書籍:Effective C#

まずは確認

プログラミングをしていると必ず学ぶメモリ管理。
ちゃんと管理しないとメモリが足りなくなる事があります。

C#のオブジェクトのおおくはGC(ガベージコレクタ)によって管理されていますが、例のごとく管理対象外オブジェクトがあります。
(例えばDB接続オブジェクトだったり)

そんなGCが管理しないオブジェクトは非マネージリソース(アンマネージリソース)って呼ばれてたりします。

そこで非マネージリソースを制御するためにC#では

  1. ファイナライザ
  2. IDisposableインタフェース

という2つの機能を用意しています。C#ではファイナライザをデストラクタとも呼びます。


今回、このファイナライザとIDisposableインタフェースを併せて実装することで良いメモリ管理ができるという話です。(むしろ王道っぽい)

問題


そもそもGCがファイナライザを呼びます。
ファイナライザが呼ばれるタイミングはオブジェクトがガベージとなった後であり
そのタイミングはわかりません。
つまり不要なオブジェクトがより長い期間メモリ上に残ってしまう問題が発生します。


そこで、ファイナライザとIDisposableをうまく使ってプログラマはメモリ解放を解決しましょう、というわけです。

Disposeパターン

本題のDisposeパターンですが、
ファイナライザが先に呼ばれても、Disposeメソッドが先に呼ばれても、
正しくメモリを解放しようという仕組みだと理解しました。

今回簡単なフローチャートを作ってみました。

ファイナライザ(デストラクタ)とDisposeメソッドの両方とも「メモリ解放処理」を呼んでいるところが味噌だと思います。

ファイナライザが呼ばれる前にDispose()が呼ばれる場合


Dispose()が呼ばれる前にファイナライザが呼ばれる場合


メモリ解放処理

具体的なメモリ解放のフローチャートは以下のようになります。

Disposeメソッドから呼ばれたときは、マネージリソースと非マネージリソースが残っているので両方解放するけど、ファイナライザから呼ばれたときは非マネージリソースだけ解放しています。
これはファイナライザが呼ばれるとマネージリソースはGCで自動的に解放されるからだと考えられます。

こんな風にファイナライザとIDisposableインタフェースを使う事で正しくメモリ管理が出来るよ、という事でした。他のJavaPythonRubyなんかはどんなメモリ管理しているのかも気になるので、あとで調べてみよ。(もしくは教えて頂けると嬉しいですw)
普段なかなか見ないメモリですが、少しでも理解を深めてプログラミングに取り組みたいです。

フローチャート作成にはblockdigを使いました。