DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Disposeにおけるマネージリソースの解放

環境/言語:[VB.NET1.1]
分類:[.NET]

Disposeのヘルプにある雛型では、
ここで、マネージリソース解放しなさいとありますが
具体的には、なにをすべきなのかはっきりしません

Disposeを実装するインスタンスを保持していたら
Disposeしておいた方が良いとは思いますが

それ以外の参照型も明示的に、Nothingにしておいた方が
より早くリソースが解放されるのでしょうか
2008/04/14(Mon) 00:32:41 編集(投稿者)

はじめまして、H.K.R.と申します。
 
 私はDispose()、Finalize()メソッドやガーベージコレクションについてあまり詳しいことはわからないので、
手元の文献で「付け焼刃で」調べてみました。
※ VB2005の文献ですが、ご了承下さい。
 
文献の記述によると、
メインアプリケーションからアクセスできないオブジェクトは、ガーベージコレクションの対象となるようです。
そのため、Dispose()メソッド内で参照型の変数に明示的にNothingを代入しなくても、以下のコードでOKのようです。
 
[ここから文献のコードを引用(一部私が追記した箇所有り)]
 
Public Class Widget
 Implements IDisposable
 
 Private disposed As Boolean
 
 Public Sub Dispose() Implements IDisposable.Dispose
  If disposed Then Exit Sub
  disposed = True
  ' ファイルを閉じるなど、リソースを解放する
 
  ・・・
  ' 基本クラスがDisposeメソッドを実装している場合は、Try-Finallyブロックを用い、
  ' 基本クラスのDisposeメソッドが必ず呼び出されるようにする。
 End Sub
End Class
 
' オブジェクトを生成する
Dim obj As New Widget()
' オブジェクトを使用する
 
・・・
' Nothingに設定する前に、オブジェクトにリソースを解放させる
obj.Dispose
obj = Nothing ' (※)
 
 
VB2005以降で、Using文を使用する場合
 
' オブジェクトを生成する
Using obj As New Widget()
 ' オブジェクトを使用する
 
 ・・・
 ' ↓ここでオブジェクトが破棄され、Nothingに設定される
End Using
 
[ここまで文献のコードを引用]
 
 VB2005の場合(VB.NET2003の場合はどうかわかりませんが、)、
Releaseモードでのコンパイル時に最適化を有効にする場合には、(※)のコードがなくても(明示的にNothingを代入しなくても)、このオブジェクトが使用されないことがVisualBasicコンパイラによって検出された場合には、変数objが参照していたオブジェクトはガーベージコレクションの対象となるようです。
 
(とりあえずの結論)
 
> それ以外の参照型も明示的に、Nothingにしておいた方が
> より早くリソースが解放されるのでしょうか
 
とりあえず、上のコードの例(※)における obj = Nothing のみでOKのようです。
(Releaseモードでのコンパイル時に最適化を有効にする場合には、これすらも不要な場合がある)
 
> 具体的には、なにをすべきなのかはっきりしません
 
[ここから文献の引用]
 .NETのプログラミングガイドラインによれば、オブジェクトのDisposeメソッドでは、そのオブジェクトによって所有され、クライアントコードに公開されないすべての内部オブジェクトのDisposeメソッドを呼び出し、続いて(基本クラスがIDisposableインターフェースを実装している場合は)基本クラスのDisposeメソッドを呼び出すことになっています。たとえば、WidgetオブジェクトがSystem.Timers.Timerオブジェクトを生成している場合は、Widget.DisposeメソッドからTimer.Disposeメソッドを呼び出します。(中略)Disposeメソッドが複数回呼び出される可能性がある(中略)複数回呼び出してもエラーにはなりませんが、1回目の呼び出し以外は無視すべきでしょう。
[ここまで文献の引用]
ということなのだそうです。あまり長々と引用するとまずいと思うので、このくらいでとどめておきます。
 
 
P.S.
 私にはここまでしかわからないので、詳しい方のフォローをいただければ幸いです。
 
参考文献
 日経BPソフトプレス発行「プログラミングVisualBasic2005言語編(上)」、pp. 403, 406, 408, 422.
 
以上です。
■No21843に返信(H.K.R.さんの記事)

>   ' ファイルを閉じるなど、リソースを解放する

そういうケースも有り得ますね

> とりあえず、上のコードの例(※)における obj = Nothing のみでOKのようです。

確かに、この時点でobj内のマネージリソースも破棄されるので
Dispose内で、Nothingしても意味ないですね

>>具体的には、なにをすべきなのかはっきりしません
>  
> [ここから文献の引用]
>  .NETのプログラミングガイドラインによれば、オブジェクトのDisposeメソッドでは、そのオブジェクトによって所有され、クライアントコードに公開されないすべての内部オブジェクトのDisposeメソッドを呼び出し、続いて(基本クラスがIDisposableインターフェースを実装している場合は)基本クラスのDisposeメソッドを呼び出すことになっています。たとえば、WidgetオブジェクトがSystem.Timers.Timerオブジェクトを生成している場合は、Widget.DisposeメソッドからTimer.Disposeメソッドを呼び出します。(中略)Disposeメソッドが複数回呼び出される可能性がある(中略)複数回呼び出してもエラーにはなりませんが、1回目の呼び出し以外は無視すべきでしょう。
> [ここまで文献の引用]
> ということなのだそうです。あまり長々と引用するとまずいと思うので、このくらいでとどめておきます。

とても丁寧に説明して頂いて、有難うございます
マネージリソースは勝手に解放されるのに...
という思いがあってこのような質問をしましたが
おかげで、納得がいきました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板