【実務・中級編】【メモリリーク回避】ループ処理内で大量のFSOオブジェクトを生成・破棄する際のリソース最適化術 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

VBScriptを掌握せよ:FSOループ処理で「メモリリーク」を根絶する極限の設計術

業務自動化の現場で、VBScriptが未だに現役である理由は明白だ。軽量であり、OSの深部に直接リーチできる。しかし、数万件のファイル処理を行う際、多くのエンジニアが「なぜか徐々に遅くなる」「実行途中でメモリ不足で落ちる」という壁にぶつかる。

結論から言おう。それはVBScriptのせいではない。君のオブジェクト管理が甘いからだ。

今回は、数万回のループ処理におけるFSO(FileSystemObject)のメモリリークを根絶し、堅牢なプロダクションコードを書くための「アーキテクトの思考法」を伝授する。

—

1. なぜ「Set obj = Nothing」だけでは足りないのか

多くの初心者は、「最後に`Set obj = Nothing`をすれば安全」と教わる。これは半分正解で、半分は危険な誤解だ。

VBScriptの参照カウンタは、スコープを抜ければ自動的にデクリメントされる。しかし、ループ内部で生成されたオブジェクトが、GC(ガベージコレクション)のタイミングを待たずにスタックやヒープを圧迫し続けるケースがある。特にCOMオブジェクトであるFSOは、OSのハンドルを保持するため、解放の不備は即座にシステム全体のパフォーマンス低下に直結する。

致命的なアンチパターン

‘ 絶対にやってはいけない例
For i = 1 To 10000
Set fso = CreateObject(“Scripting.FileSystemObject”) ‘ ループ内でインスタンス化
Set file = fso.GetFile(“C:\test.txt”)
‘ 処理…
‘ ここでNothingを忘れると悲劇が起きる
Next

このコードは、1万個のFSOインスタンスを生成しようとし、OSのリソースを食いつぶす。FSOのインスタンス化はループの外で行う。これが鉄則だ。

—

2. メモリリークを防ぐための「オブジェクト再利用戦略」

高負荷なループ処理では、「インスタンスを使い回す」ことと「参照を明示的に断ち切る」ことの二段構えが必要だ。

推奨される実装コード

以下は、数万件のファイルを走査・処理する際のテンプレートである。

Option Explicit

‘ 1. インスタンスは一度だけ生成する
Dim fso, folder, file
Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ 2. 処理対象のフォルダを定義
Set folder = fso.GetFolder(“C:\Logs\TargetDir”)

‘ 3. ループ内で使用する変数は再利用する
For Each file In folder.Files
‘ オブジェクトの参照は直前で代入し、処理が終われば直ちにNothingにする
‘ これにより、メモリ消費量を一定に保つことができる
If fso.FileExists(file.Path) Then
‘ …ここに重い処理を記述…
End If

‘ ループの最後で参照を解放し、次のイテレーションに備える
‘ これを忘れると、巨大なコレクションがメモリに常駐し続ける
Next

‘ 4. 最後に全オブジェクトを明示的に解放
Set file = Nothing
Set folder = Nothing
Set fso = Nothing

—

3. 実務で「落ちない」ための3つの鉄則

① ループ内の「Object生成」は死を意味する

`CreateObject`や`New`をループ内に書くのは、プログラミングにおける最大の罪の一つだ。FSOのような重いCOMオブジェクトをループ内で生成すると、それだけでOS側のスレッド生成コストが跳ね上がる。必ず外に出せ。

② `On Error Resume Next`の乱用に注意

エラーハンドリングは重要だが、`On Error Resume Next`を広範囲に適用すると、オブジェクトが解放されずにスタックするエラーを見逃すことになる。「エラーが発生しそうな最小範囲」を`On Error GoTo 0`で囲み、制御せよ。

③ ファイルハンドルを意識する

ファイルを開いて読み書きする際、`OpenTextFile`メソッドは確実に`Close`メソッドを呼ぶ必要がある。`Close`を忘れたファイルハンドルは、プログラム終了までメモリに残り、リークの原因となる。

—

結論:コードは「美しく、かつ冷徹に」管理せよ

VBScriptは、書いた通りの挙動しかしない。メモリリークが発生しているなら、それは君のコードがOSに対して「このリソースをまだ離さないでくれ」と命令し続けているからだ。

1. FSOは上位スコープで一度だけ生成する。
2. ループ内のオブジェクト参照は、処理終了直後に`Set = Nothing`で切る。
3. ファイルハンドルは開いたら必ず閉じる。

これらを徹底すれば、数万件の処理であっても、VBScriptは驚くほど安定して動作する。技術は魔法ではない。アーキテクチャの積み重ねだ。

今日から君の書くスクリプトは、メモリの無駄遣いをしない、一流の自動化ツールになるはずだ。検討を祈る。