【入門編】オブジェクト変数のSetとNothing:メモリリークを確実に防ぐ作法 – Excel VBA解析バイブル

スポンサーリンク

こんにちは!Excel VBAの自動化を進めていくと、「動くには動くけれど、なんだか最近Excelの動作が重いな…」「タスクマネージャーを見ると、Excelのプロセスが裏に残っている気がする…」そんな怪奇現象に悩まされたことはありませんか?

マクロの記録から一歩踏み出し、WorksheetやWorkbookといった「オブジェクト変数」を使いこなせるようになったあなたへ。今回は、プロのエンジニアが必ず守っている「メモリ管理の極意」をお伝えします。

ここをクリアすれば、あなたの書くVBAコードは一段と洗練され、トラブル知らずの堅牢なシステムに生まれ変わります。一緒に本質をマスターしていきましょう!

1. なぜオブジェクト変数には「Set」が必要なのか?

まず、VBAの「変数」に対する基本的な考え方をアップデートしましょう。
普段私たちが使う `Dim i As Long` や `Dim name As String` といった変数は、メモリ上の「入れ物そのもの(値)」を直接保持します。これを値型(プリミティブ型)と呼びます。

一方、Excelのシートやブック、セル範囲などは、データ量が大きく構造も複雑です。これらをそのまま変数に入れようとすると、メモリがパンクしてしまいます。
そのため、VBAでは「オブジェクトの実体は別の場所に置いておき、変数にはその『ありか(アドレス)』だけを教える」という方式をとっています。これが参照型です。

ここで登場するのが、お馴染みの `Set` キーワードです。

‘ ❌ エラーになる書き方
Dim ws As Worksheet
ws = ThisWorkbook.Sheets(“集計”)

‘ ⭕ 正しい書き方
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(“集計”)

図解:変数とオブジェクトの関係

[あなたのコード (変数 ws)] ───(リモコン)───> [Excelのメモリ上の実体 (Sheetオブジェクト)]

`Set` は、言ってみれば「リモコン(変数)に、テレビ(オブジェクト実体)のチャンネルを合わせる行為」です。この仕組みを理解しておくと、後述するメモリリークの話がスッと腑に落ちるようになります。

2. メモリリークの恐怖:使った後は「Nothing」で解放せよ

さて、ここからが今回の本題です。
あなたがコードの中で `Set ws = …` と書いた瞬間、Excelはそのオブジェクトをメモリ上に確保し、VBAからアクセスできるようにします。

では、マクロの処理が終わったとき、そのメモリはどうなるでしょうか?
「VBAのプロシージャ(Sub〜End Sub)が終われば、自動的に消えてくれるんでしょ?」
実は、半分正解で半分間違いです。

VBAの単純なプロシージャ内であれば、終わった瞬間に一括してメモリが解放されることも多いのですが、以下のようなシチュエーションではメモリが解放されずに残り続け、パソコンのメモリを少しずつ食いつぶしていく「メモリリーク」が発生します。

1. 複数のブックやExcelアプリケーションをまたいで操作しているとき(特に `CreateObject(“Excel.Application”)` などを使った外部操作)
2. ループ処理の中で何度もオブジェクトを生成・再代入しているとき
3. クラスモジュールやグローバル変数にオブジェクトを保持させているとき

メモリ解放の呪文:`Set 〇〇 = Nothing`

オブジェクト変数を用済みになったら、「もうこのリモコンは使いません。実体との接続を断ち切ってください」とVBAに明示してあげる必要があります。それが `Nothing` の代入です。

Sub CleanMemorySample()
Dim wb As Workbook
Set wb = Workbooks.Open(“C:\Data\Report.xlsx”)

‘ — 何らかのデータ処理 —
wb.Sheets(1).Range(“A1”).Value = “処理完了”
wb.Save

‘ 処理が終わったら閉じる
wb.Close SaveChanges:=False

‘ 【重要】メモリから参照を完全に切り離す
Set wb = Nothing

MsgBox “処理が正常に終了し、メモリも綺麗に解放されました!”, vbInformation
End Sub

`Set wb = Nothing` を実行すると、変数 `wb` とExcel上のファイル実体のつながりがプツリと切れます。これにより、OSは「あ、もうこのメモリ領域は必要ないんだな」と判断し、綺麗に回収(ガベージコレクション)してくれるのです。

3. 実務で絶対に出会う!「裏でExcelが終了しない現象」の正体

実務でVBAを書いていると、以下のようなコードを書く機会があるはずです。別のExcelファイルをVBAから操作してデータを抜き出すようなケースですね。

Sub BadExample()
Dim appEx As Object
Dim wbEx As Workbook

‘ 別Excelを起動
Set appEx = CreateObject(“Excel.Application”)
Set wbEx = appEx.Workbooks.Open(“C:\Data\Target.xlsx”)

‘ 何か処理をする
MsgBox wbEx.Sheets(1.Range(“A1”).Value

‘ ブックを閉じてアプリも終了する
wbEx.Close False
appEx.Quit

‘ ★ここで終わりにしていませんか?
End Sub

上記のコードを実行した後、タスクマネージャーを開いてみてください。
「EXCEL.EXE」というプロセスが、タスクの裏側にゾンビのように残っていませんか?

これが、現場のエンジニアを長年悩ませてきた「Excelプロセスのメモリリーク」です。
VBA側から `appEx.Quit` と指示を出したつもりでも、変数 `appEx` や `wbEx` がメモリ上でまだ「参照」を保持し続けているため、Windowsは「まだこのプロセスは使われているかもしれない」と勘違いして終了させずに残してしまうのです。

プロフェッショナルの模範解答コード

この恐怖のゾンビプロセスを防ぐためには、生成した順番とは逆の順番で、確実に `Nothing` を代入するのが鉄則です。

Sub GoodExample()
Dim appEx As Object
Dim wbEx As Workbook

On Error GoTo ErrorHandler ‘ エラー時にも確実に解放処理へ飛ばすお作法

‘ 1. オブジェクトの生成
Set appEx = CreateObject(“Excel.Application”)
Set wbEx = appEx.Workbooks.Open(“C:\Data\Target.xlsx”)

‘ 2. 処理
MsgBox wbEx.Sheets(1).Range(“A1”).Value

‘ 3. 通常のクローズ処理
wbEx.Close False
appEx.Quit

ErrorHandler:
‘ 4. エラーが起きようが起きまいが、確実に逆順で Nothing を代入
Set wbEx = Nothing
Set appEx = Nothing

If Err.Number <> 0 Then
MsgBox “エラーが発生しましたが、メモリリークは防止されました。Error: ” & Err.Description, vbCritical
End If
End Sub

生成したオブジェクトは、「作ったら最後、必ず `Nothing` で始末をつける」。この習慣をつけるだけで、あなたの書くマクロの信頼性はプロのレベルへと一気に跳ね上がります。

まとめ:ここをクリアすれば、VBAの基本はバッチリ!

今回は、オブジェクト変数の `Set` と `Nothing`、そしてメモリ管理の本質について解説しました。

  • オブジェクト変数は「リモコン(参照型)」であるため、`Set` で紐付ける必要がある。
  • 使い終わったオブジェクトは、放置するとメモリリークやプロセス残留(ゾンビ化)の原因になる。
  • プロシージャの最後やエラー処理(`On Error GoTo`)の中で、必ず `Set 〇〇 = Nothing` を行い、きれいに後片付けをする。

最初は少し面倒に感じるかもしれませんが、「使ったら片付ける」というエンジニアの美しい美学は、必ずあなた自身を助けてくれます。

ここをクリアすれば、Excel VBAの基本的な概念や作法はもうバッチリです!自信を持って、日々の業務自動化に挑んでいきましょう。あなたのVBAライフが、快適でエラー知らずなものになることを応援しています!

タイトルとURLをコピーしました