MemoryFailPoint クラス (System.Runtime)
MSDN より抜粋
MemoryFailPoint クラスのインスタンスを作成すると、メモリ ゲートが作成されます。メモリ ゲートとは、大量のメモリを必要とするアクティビティを開始する前に、十分なリソースがあるかどうかをチェックすることです。チェックに合格しなかった場合、操作を開始できないようにする InsufficientMemoryException がスローされるため、リソース不足が原因となってアプリケーションが実行中に失敗する可能性が減少します。これにより、アプリケーションでは、パフォーマンスを低下させ、OutOfMemoryException や、コード内の任意の場所で OutOfMemoryException を誤って処理したことが原因で発生する状態の破損を避けることができます。
つまり、OutOfMemoryException という、ある意味天災的な例外を、事前に察知するためのクラスです。
処理を開始する前にこれを察知できるというのは、場合によっては大きなメリットとなりそうです。
ただし、MemoryFailPoint が InsufficientMemoryException をスローしなかった場合でも、メモリは論理的には確保されていますが物理的に確保されているわけではありません。従って、 OutOfMemoryException がスローされる可能性も残っているということです。
このクラス自体の使い方は簡単です。
コンストラクタ でメモリーサイズ ( 単位はMB ) を指定します。指定したサイズのメモリーが使用できない場合は、InsufficientMemoryException クラス (System) がコンストラクタからスローされます。
なお、使用後は必ず Dispose メソッド を呼び出す必要があることに注意します。 ( InsufficientMemoryException が発生したら呼べないけど、コンストラクタが例外投げた場合、CLR は即座にファイナライザを呼び出すから問題無し。 → 勘違いでした。CLR は即座にファイナライザを呼び出したりはしません。でも、例外が発生したらリソース確保もされないと思います。 )
ちなみに、InsufficientMemoryException は OutOfMemoryException の派生クラスです。
[ 参考 ]
プログラミング Microsoft .NET Framework 第2版
オブジェクトのメモリは、そのオブジェクトがアクセス可能である限り、回収されることはない。オブジェクトがアクセス不可能になるとオブジェクトのメモリはGCの対象となり、適切なタイミングでGCが回収してくれる。
変数(フィールドやらローカル変数やら)に格納されている参照のことを「強い参照」と言う。
「アクセス可能なオブジェクト」とは、強い参照が存在するオブジェクトのことを言う。ただし、その強い参照を所持しているオブジェクトもアクセス可能なオブジェクトである必要がある。つまり、強い参照を所持しているオブジェクトを辿って行くとアクセス不可能なオブジェクトに辿り着く場合、それらは全てアクセス不可能なオブジェクトである。また、実際にアクセスされている最中(コンストラクタ実行中だったりメソッド実行中だったり)のオブジェクトも、アクセス可能なオブジェクトである。
冒頭でも書いたとおり、アクセス可能なオブジェクトはGCの対象にはならない。
しかし、「強い参照」が存在せず「弱い参照」が存在するオブジェクトなら、弱い参照を通して呼び出すことができる上、GCの対象となる。
「弱い参照」とは、WeakReferenceクラスによる参照である。WeakReferenceは、コンストラクタで対象オブジェクトを受け取る。WeakReferenceオブジェクトのTargetプロパティを通して対象オブジェクトにアクセスできるのだが、WeakReferenceオブジェクトは、内部に強い参照を保持するのではなく、参照をIntPtr構造体として保持している。これにより、対象オブジェクトはGCの対象となる。
対象オブジェクトがGCの対象となるので、GCによって対象オブジェクトのメモリが回収された場合は、Targetプロパティはnull参照を返す。そのため、対象オブジェクトにアクセスする際は、Targetプロパティから強い参照を取得して、強い参照を通してアクセスする必要がある。
具体的には、まずTargetプロパティを変数に代入して強い参照を取得する。そして、その変数の値がnull参照であった場合は、再び対象オブジェクトを生成する。その後、その変数を通して対象オブジェクトにアクセスし、最後に強い参照を消去する(変数にnull参照を代入したり、ローカル変数ならスコープ外に処理が移れば勝手に消える)。
弱い参照の作成・使用の例
class Piyo
{
// Hogeオブジェクトへの弱い参照
private WeakReference weakHoge;
// コンストラクタ
public Piyo()
{
Hoge hoge = this.CreateHoge();
this.weakHoge = new WeakReference(hoge);
hoge = null;
}
// Hogeオブジェクトを使うメソッド
public void UseHoge()
{
Hoge hoge = (Hoge)this.weakHoge.Target;
if (hoge == null)
{
hoge = this.CreateHoge();
this.weakHoge.Target = hoge;
}
//
// Hogeを使った処理
//
hoge = null;
}
// Hogeオブジェクトを生成するメソッド
private Hoge CreateHoge()
{
Hoge hoge = new Hoge();
hoge.Name = "ほげ"
return hoge;
}
}
IsAliveプロパティを使って、対象オブジェクトがGCに回収されているかどうかを調べたり、直接Targetプロパティとnullを比較することもできるが、これらのプロパティにアクセスした時は回収されていなくても、直後に回収されてしまうというケースもありえる。なので、上記の例のように最初にTargetプロパティから強い参照を取得する必要がある。(強い参照の取得さえちゃんとすれば、IsAliveやTargetとの比較を用いても問題ない。)
弱い参照を使用するシーンとしては、サイズの大きなオブジェクトを保持して利用する際に、そのオブジェクトが常にメモリを占有してしまうよりは、GCの対象としておき、回収された場合は再び作成するという手段を取った方が、作成にかかるコストを考慮しても有益だという場合などである。