オブジェクトの有効期間 : オブジェクトの作成と破棄

更新 : 2007 年 11 月

クラスのインスタンス、つまりオブジェクトを作成するには New キーワードを使用します。通常は、新しいオブジェクトを使用する前に初期化する必要があります。一般的な初期化のタスクとしては、ファイルを開く、データベースに接続する、レジストリ キーの値を読み取るなどがあります。Visual Basic では、新しいオブジェクトの初期化処理をコンストラクタと呼ばれるプロシージャによって制御します。コンストラクタとは、初期化を制御するための特殊なメソッドです。

スコープを離れたオブジェクトは、共通言語ランタイム (CLR: Common Language Runtime) によって解放されます。Visual Basic では、システム リソースの解放をデストラクタと呼ばれるプロシージャによって制御します。コンストラクタとデストラクタは、堅牢で予測可能なクラス ライブラリを作成するのに役立ちます。

Sub New と Sub Finalize

Visual Basic では、Sub New プロシージャと Sub Finalize プロシージャがオブジェクトの初期化と破棄を行います。これらは、Visual Basic 6.0 以前のバージョンで使用されていた Class_Initialize メソッドと Class_Terminate メソッドに代わるものです。Class_Initialize とは異なり、Sub New コンストラクタはクラスが作成されるときに 1 回だけ実行されます。同じクラスまたは派生クラスの別のコンストラクタの 1 行目に記述して呼び出す以外に、これを明示的に呼び出す方法はありません。また、Sub New メソッド内のコードは常に、クラス内の他のすべてのコードより先に実行されます。クラスの Sub New プロシージャを明示的に定義しなかった場合、Visual Basic 2005 以降のバージョンでは、実行時に Sub New コンストラクタが暗黙的に作成されます。

オブジェクトを解放する前に、CLR は Sub Finalize プロシージャを定義するオブジェクトの Finalize メソッドを自動的に呼び出します。Finalize メソッドには、オブジェクトを破棄する直前に実行する必要があるコードを記述できます。これらのコードでは、ファイルを閉じたり、状態情報を保存したりします。Sub Finalize の実行には、わずかながらパフォーマンス上の不利があります。そのため、オブジェクトを明示的に解放する必要がある場合にのみ Sub Finalize メソッドを定義してください。

hks5e2k6.alert_note(ja-jp,VS.90).gifメモ :

オペレーティング システムが CLR 環境の外部で直接実行しているオブジェクトをアンマネージ オブジェクトといいますが、CLR 内のガベージ コレクタはアンマネージ オブジェクトを破棄しません (できません)。これは、アンマネージ オブジェクトは種類ごとに異なる方法で破棄する必要があるからです。そのような情報はアンマネージ オブジェクトに直接関連付けられているわけではなく、オブジェクトのドキュメントで調べる必要があります。アンマネージ オブジェクトを使用するクラスは、Finalize メソッドを使用してオブジェクトを破棄する必要があります。

Finalize デストラクタは、属しているクラスまたは派生クラスからのみ呼び出し可能なプロテクト メソッドです。オブジェクトが破棄されるときに、システムは Finalize を自動的に呼び出します。したがって、派生クラスの Finalize 実装の外部から、明示的に Finalize を呼び出す必要はありません。

オブジェクトが nothing に設定されるとすぐに実行される Class_Terminate とは異なり、通常、オブジェクトがスコープ外になってから Visual Basic が Finalize デストラクタを呼び出すまでには遅延があります。Visual Basic 2005 以降のバージョンには、Dispose というもう 1 種類のデスクトラクタがあります。このデストラクタは、リソースをすぐに解放する必要がある場合にいつでも明示的に呼び出すことができます。

hks5e2k6.alert_note(ja-jp,VS.90).gifメモ :

Finalize デストラクタからは例外をスローしません。アプリケーションは例外を処理できないので、それが原因で異常終了する可能性があります。

IDisposable インターフェイス

クラス インスタンスは、Windows ハンドルやデータベース接続など、CLR では管理されないリソースを制御する場合があります。このようなリソースはクラスの Finalize メソッド内で破棄する必要があります。これにより、オブジェクトがガベージ コレクタによって破棄されるときにリソースが解放されます。ただし、ガベージ コレクタがオブジェクトを破棄するのは、CLR がより多くの空きメモリを必要とするときに限られます。そのため、オブジェクトがスコープ外になった後、しばらく経ってもリソースが解放されない可能性があります。

クラスが IDisposable インターフェイスを実装している場合は、ガベージ コレクションを補うために、システム リソースをアクティブに管理するしくみを用意できます。IDisposable には、クライアントがオブジェクトの使用を終了するときに呼び出す Dispose メソッドが含まれています。Dispose メソッドを使用すると、即座にリソースを解放して、ファイルやデータベース接続を閉じるなどのタスクを実行できます。Finalize デストラクタとは異なり、Dispose メソッドは自動的には呼び出されません。クラスのクライアントは、リソースを即座に解放するときに、明示的に Dispose を呼び出す必要があります。

IDisposable の実装

IDisposable インターフェイスを実装するクラスには、次のコード セクションを含める必要があります。

  • オブジェクトが破棄されたかどうかを追跡するためのフィールド。

    Protected disposed As Boolean = False
    
  • クラスのリソースを解放するオーバーロードされた Dispose メソッド。このメソッドは基本クラスの Dispose メソッドおよび Finalize メソッドから呼び出す必要があります。

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposed Then
            If disposing Then
                ' Insert code to free managed resources.
            End If
            ' Insert code to free unmanaged resources.
        End If
        Me.disposed = True
    End Sub
    
  • Dispose の実装。次のコードだけを含みます。

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
    
  • オーバーライドされた Finalize メソッド。次のコードだけを含みます。

    Protected Overrides Sub Finalize()
        Dispose(False)
        MyBase.Finalize()
    End Sub
    

IDisposable を実装するクラスからの派生

IDisposable インターフェイスを実装する基本クラスから派生したクラスは、基本メソッドをオーバーライドする必要はありません。ただし、追加リソースを使用していて、そのリソースを破棄する必要がある場合は別です。その場合は、派生クラスは基本クラスの Dispose(disposing) メソッドをオーバーライドして、派生クラスのリソースを破棄するようにします。このオーバーライドされたメソッドでは、基本クラスの Dispose(disposing) メソッドを呼び出す必要があります。

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If Not Me.disposed Then
        If disposing Then
            ' Insert code to free managed resources.
        End If
        ' Insert code to free unmanaged resources.
    End If
    MyBase.Dispose(disposing)
End Sub

派生クラスでは、基本クラスの Dispose および Finalize メソッドをオーバーライドしないでください。派生クラスのインスタンスからこれらのメソッドを呼び出したときは、これらのメソッドの基本クラスの実装が、派生クラスのオーバーライドされた Dispose(disposing) メソッドを呼び出します。

ビジュアル化

次の図は、派生クラスの中でどのメソッドが継承され、どのメソッドがオーバーライドされているかを示しています。

破棄可能な継承グラフィック

この DisposeFinalize パターンに従えば、派生クラスおよび基本クラスのリソースが正しく破棄されます。次の図は、クラスが破棄されて終了されるときにどのメソッドが呼び出されるかを示しています。

破棄可能な呼び出しグラフィック

ガベージ コレクションと Finalize デストラクタ

.NET Framework では、使われていないリソースを定期的に解放するために参照トレース ガベージ コレクションというシステムを使用しています。Visual Basic 6.0 以前のバージョンでは、参照カウントと呼ばれる別のシステムを使用してリソースを管理していました。どちらのシステムも同じ機能を自動的に実行しますが、いくつかの重要な違いがあります。

CLR は、システムが不要と判断したオブジェクトを定期的に破棄します。オブジェクトは、システム リソースが不足する場合は短い周期で解放され、そうでない場合は長い周期で解放されます。オブジェクトがスコープを失ってから CLR が解放するまでの遅延があるため、Visual Basic 6.0 以前のバージョンのオブジェクトとは異なり、オブジェクトがいつ破棄されるかを正確には判断できません。このような場合、オブジェクトは未決定の有効期間を持つことになります。ほとんどの場合、オブジェクトがスコープを失っても Finalize デストラクタがすぐに実行されない場合があることを覚えている限り、未決定の有効期間を考慮してアプリケーションの記述方法を変える必要はありません。

ガベージ コレクション システムとの違いは、Nothing の使用方法にもあります。Visual Basic 6.0 以前の参照カウント システムを利用するには、オブジェクト変数に Nothing を代入することで、その変数に保持されている参照を解放するという方法があります。この変数がオブジェクトへの最後の参照を保持している場合、オブジェクトのリソースは直ちに解放されます。現在のバージョンの Visual Basic では、この方法が有効な場合もありますが、参照されたオブジェクトのリソースはすぐには解放されません。リソースを直ちに解放するためには、オブジェクトの Dispose メソッドを使用します (使用可能な場合)。変数を Nothing に設定する必要があるのは、ガベージ コレクタが孤立したオブジェクトを検出するまでにかかる時間よりも、変数の有効期間が長い場合だけです。

参照

処理手順

方法 : Dispose Finalize パターンを実装する (Visual Basic)

概念

コンポーネントの初期化と終了

Finalize メソッドおよびデストラクタ

参照

コンストラクタとデストラクタの使用方法

New (Visual Basic)

Dispose

Nothing (Visual Basic)

その他の技術情報

言語の変更点 (Visual Basic 6.0 ユーザー向け)