「Set a = Nothing」のお話|Excel VBA |
変数は大きく分けて2種類あります。
1つは値を格納する変数、もう1つはオブジェクトへの参照を格納する変数です。
後者をオブジェクト変数といいます。それぞれの変数の特徴や代入方法については
「VBA最初の一歩(その5)変数と宣言」を参照してください。
ここでは、オブジェクト変数について取りあげます。次のサンプルをご覧ください。
Sub Sample1()
Dim objIE As Object
Dim buf As String
Set objIE = CreateObject("InternetExplorer.Application") '--(1)
objIE.Visible = False
objIE.navigate "http://vbae.odyssey-com.co.jp/column/"
Do While objIE.busy
DoEvents
Loop
Do While objIE.Document.readyState <> "complete"
DoEvents
Loop
buf = objIE.Document.body.innerText
objIE.Quit
Set objIE = Nothing '--(2)
'IEから取得したデータをもとに何か処理を行う場合は
'ここに記述します
End Sub
オブジェクト変数には、セル(Rangeオブジェクト)やワークシート(Worksheetオブジェクト)などExcelのもつオブジェクトのほか、外部オブジェクトへの参照を設定できます。
オブジェクトへの参照を設定するには、Setステートメントを使用します。
Sample1では、(1)でInternet Explorerのオブジェクトを作成し、そのオブジェクトへの参照をオブジェクト変数objIE に設定しています。
これ以降、変数objIE を使ってInternet Explorerオブジェクトの持つプロパティやメソッドを呼び出すことが可能になります。
オブジェクトへの参照を解除するには、次のように記述します。
Set オブジェクト変数 = Nothing
「Nothing」は、オブジェクト変数がどのオブジェクトも参照していないことを表す特別な値です。オブジェクト変数を宣言した後、オブジェクトへの参照が設定されるまで、オブジェクト変数にはNothingが設定されています。
上記のようにSetステートメントでNothingを設定することで、オブジェクト変数と参照先のオブジェクトとの関係が無効になります。
このとき、参照先のオブジェクトをメモリ上から削除(破棄)しているわけではありません。
次のサンプル2で試してみましょう。
2つのオブジェクト変数aとbは同じオブジェクトを参照しています。
「Set a = Nothing」をすると変数aからオブジェクトへの参照を解除しますが、参照先のオブジェクトは残ります。変数bからオブジェクトへの参照も有効なので、変数bを使って別のWebページの表示が可能です。
実行する際は、Webページの表示後、ExcelまたはVBEをアクティブにしてください。
Sub Sample2()
Dim a As Object, b As Object
'---aとbは同じオブジェクトを参照
Set a = CreateObject("InternetExplorer.Application")
Set b = a
a.Navigate "http://vbae.odyssey-com.co.jp/column/"
b.Visible = True
'---aにNothingをセットした後も、bを使ってIEを操作できる
Set a = Nothing
MsgBox "Set a=Nothing を実行しました"
b.Navigate "http://vbae.odyssey-com.co.jp/column/no1_1.html"
MsgBox "bを使って別のWebページを表示しました"
b.Quit 'IEを終了
End Sub
では、オブジェクトが破棄されるのはいつでしょう?
それは、オブジェクトがどこからも参照されなくなったときです。
多くのオブジェクトはそのタイミングで自分自身を破棄するのに必要な処理を行います。
「Set a = Nothing」は、いわば「もう、このオブジェクトを参照するの、やーめた!」という処理になります。
「Set a = Nothing っているの?いらないの?」よくある質問ですね。
これに対して「ぜったい書くべき!」必要派 と 「まったく意味ない!」不要派 の議論を時おり目にしますが、以下はゼロかイチか、白か黒かではない「Set a = Nothing」のお話です。
変数には有効期間があり、有効期間が終了すると、オブジェクトへの参照が正常に解除される仕組みがあります。プロシージャレベル変数の場合、そのタイミングは「End Sub」です。
よく「End Sub」の直前に、プロシージャ内で使用したすべてのオブジェクト変数をまとめて解除する例が見られますが、オブジェクトの使用が終わってすぐにプロシージャも終了するなら、そこで自動的に解除されるので、「Set a = Nothing」 は必ずしも必要ないでしょう。
ただし、オブジェクト変数が有効である間は、変数はずっとそのオブジェクトを参照し続けている状態となります。
オブジェクトは、どこからも参照されなくなったときに、自分自身を破棄する仕組みになっているので、使わなくなったオブジェクト変数を放っておくと、その分だけ効率が落ちる可能性があることになります。
そのため、「Set a = Nothing」をして、早め早めにオブジェクトへの参照を解除することで効率化につながります。特に、多くのリソースを使用するオブジェクトは、早めに参照を解除すると良いでしょう。
それは、以降の処理でそのオブジェクトを使用しないことを明示することにもなり、メンテナンス性においてもプラスになるでしょう。
ここでもう一度、サンプル1を見てみましょう。
Internet ExplorerをQuitメソッドで終了した直後にNothingをセットし、その後なんらかの処理を行っています。このように、「Set a = Nothing」を記述する位置は、必要なオブジェクト操作が終わったすぐ後が良いでしょう。
使い終わったらすぐにお片付け。プログラミングだけでなく、心がけたいですね。
Nothingの代入が必須のケースもあります。
オブジェクトが互いのオブジェクトを参照している「循環参照」の場合、変数の有効期間が終了してもオブジェクトは破棄されません。オブジェクトがメモリ上に残り続け、オブジェクトを破棄する際に行われる処理も実行されないままになってしまいます。
この場合は、オブジェクトAからオブジェクトBを参照しているところ(またはその逆)にNothingを代入し、循環参照を断ち切る必要があります。