ガベージコレクタの収集対象・マネージリソースは、.NETランタイム上で作成されるオブジェクト(=.NETランタイム内で確保され、.NETランタイムにより管理されるメモリ領域)に限られます。 一方、ファイルハンドルやソケットなどのOS資源は、(.NETランタイムではなく)OS側で管理されているものであるため、ガベージコレクタの収集対象外・アンマネージリソースとなります。 こういったアンマネージリソースを確保する場合は、確保した側が破棄・解放の責任を負います。

一例として、ファイルハンドルと、それを扱う操作を提供するFileStreamクラスの場合を見てみます。 FileStreamでは、インスタンスの作成時にその内部でファイルハンドルの取得が行われ、FileStreamのメソッドを呼び出すことによりそのファイルハンドルを経由したファイル操作が行われます。

FileStreamクラスによって保持されているファイルハンドルは、FileStreamクラスが破棄される時点でFileStreamクラス自身によって解放されます。 FileStreamクラスがファイルハンドルの確保から解放までの責任を負っているため、このクラスを使う側(および.NETランタイム)は直接ファイルハンドルの管理には関与しません。

上記の例では、FileStreamが解放されるまでの間、ファイルハンドルは保持されたままになります。

FileStreamを含め、一般にIDisposableインターフェイスを持つオブジェクトは、usingステートメント内で使用するなどして、保持しているアンマネージリソースが解放されるよう、必ずいずれかのタイミングでDisposeメソッドが呼び出されるようにします。

FileStreamクラスを使ったファイル入出力の具体例はFileStreamクラスStreamReaderクラス・StreamWriterクラスを参照してください。

別の例として、Marshal.Alloc*()等のメソッドでユーザーが独自に確保したメモリ領域も、アンマネージリソースとなります。 Marshal.Alloc*は.NETランタイムが管理するメモリ領域ではなく、(.NETランタイムではない何らかの)アロケータが管理するメモリ領域を取得するため、ガベージコレクタの収集対象外となります。 この場合、解放の責任を負うのはメソッドを呼び出したユーザー自身となるため、ユーザー自身がMarshal.Free*()等のメソッドで解放する必要があります。

ユーザーコードでアンマネージリソースを扱う
using System;
using System.Runtime.InteropServices;

class Sample {
  static void Main()
  {
    const int length = 8;

    // アンマネージメモリ領域を確保する
    IntPtr ptr = Marshal.AllocHGlobal(length);

    // アンマネージメモリ領域を解放する
    Marshal.FreeHGlobal(ptr);
  }
}