大量図面一括変換における「メモリリーク」の呪縛を解く:セッション・リフレッシュ戦略
「数千枚の図面を、最新のDWG形式に一括変換するツールを作りました。しかし、300枚を超えたあたりでAutoCADが重くなり、最後にはクラッシュして止まってしまいます。原因は何でしょうか?」
もしあなたが、このような相談をエンジニアから受けたなら、私は即座にこう答えるだろう。
「君は、オブジェクトのライフサイクルではなく、プロセスの寿命を設計していない」と。
AutoCAD VBAの世界において、単なる `For Each` ループによるファイル処理は、未熟なエンジニアが陥る最大の罠だ。AutoCADという巨大なアプリケーション、その内部に蓄積される膨大なキャッシュ、COMオブジェクトの参照残存、そしてUndoスタック……これらが複雑に絡み合い、メモリは雪だるま式に膨れ上がっていく。
本稿では、数千枚規模のバッチ処理を「完遂」させるために必要な、「Orchestrator(オーケストレーター)パターン」による設計思想と、その実装コードを伝授する。
1. なぜ、あなたのバッチ処理は「死ぬ」のか
なぜ、単純なループ処理ではメモリ枯渇(Memory Exhaustion)が起きるのか。その理由は、AutoCADのアーキテクチャの本質にある。
COMオブジェクトの「残留」
VBAから図面(Document)やエンティティ(Entity)を操作する際、それらはすべてCOM(Component Object Model)を介して制御される。コード上で `Set obj = Nothing` と記述したとしても、AutoCAD内部のメモリ管理や、他の非表示の参照、あるいはエラー発生時のスタックによって、オブジェクトが完全に解放されないケースが多々ある。
内部キャッシュとUndoスタックの肥大化
図面を開き、保存し、閉じる。この一連の動作を繰り返すだけで、AutoCADの内部メモリには「以前のセッションの残骸」が蓄積される。特に、図面変換(Version Conversion)を行う場合、データベースの再構築が頻繁に発生し、メモリの断片化(Fragmentation)が加速する。
結論:単一のAutoCADプロセスで長時間稼働させることは、物理的に不可能である。
2. 解決策:Orchestrator(指揮者)によるセッション制御
堅牢な設計とは、エラーが起きないように祈ることではない。「エラーが起きても、システム全体が崩壊しないように設計すること」だ。
我々が採用すべきは、「AutoCAD本体」と「制御プログラム(Orchestrator)」を分離する設計である。
アーキテクチャの分離
1. Orchestrator (Excel VBA または VBScript):
- 処理対象のリスト(CSV/DB)を管理する。
- AutoCADプロセスを起動・終了する権限を持つ。
- 「どのファイルまで完了したか」というステータス(チェックポイント)を保持する。
2. Worker (AutoCAD VBA):
- 単一の図面に対して、指定された変換処理を実行する「職人」に徹する。
- 副作用を最小限にし、処理が終われば即座に制御をOrchestratorに返す。
これにより、一定数(例えば50枚ごと)の処理が終わるたびに、AutoCADプロセス自体を完全に終了(Terminate)させ、メモリをOSに完全に返却することが可能になる。
3. 実装への道:プロダクション・グレードのコード例
ここでは、Excel VBAをOrchestratorとし、AutoCADをWorkerとして制御する、実戦的な実装例を示す。
A. Worker側:AutoCAD内の標準モジュール
このコードは、AutoCAD内で実行される。役割は「一つの図面を確実に処理すること」に限定する。
' [AutoCAD VBA側]
' 引数: targetPath (変換対象ファイル), savePath (保存先), targetVer (保存形式)
Public Sub BatchConvertWorker(targetPath As String, savePath As String, targetVer As Integer)
On Error GoTo ErrorHandler
Dim dwgDoc As AcadDocument
Set dwgDoc = ThisDrawing ' 現在開いている図面
' 1. 図面の整合性チェック(Audit)
dwgDoc.Audit True
' 2. 不要な要素のパージ(メモリ節約のため)
' ※ 必要に応じて、特定のレイヤーやブロックを削除するロジックを追加
' 3. 名前を付けて保存 (SaveAs)
' AutoCADのバージョン定数を使用して保存
dwgDoc.SaveAs savePath, targetVer
' 4. 明示的なクリーンアップ
' オブジェクト参照を切り離す
Set dwgDoc = Nothing
Exit Sub
ErrorHandler:
' エラー情報を呼び出し元(Orchestrator)へ伝えるため、
' 必要に応じてログファイルや特定のセルへ書き出す設計にする
Err.Raise Err.Number, "BatchConvertWorker", Err.Description
End Sub
B. Orchestrator側:Excel VBA
ここが「脳」となる。AutoCADのライフサイクルを管理する。
' [Excel VBA側]
Option Explicit
Sub RunMassiveBatchProcess()
Dim acadApp As Object
Dim targetFiles As Collection
Dim i As Long
Dim batchSize As Integer: batchSize = 50 ' 50枚ごとにAutoCADを再起動
Dim currentBatchCount As Integer: currentBatchCount = 0
Dim filePath As String
Dim savePath As String
' 1. 処理リストの構築(本来はDBやCSVから読み込む)
Set targetFiles = LoadFileList("C:\Work\InputFiles\")
On Error Resume Next
For i = 1 To targetFiles.Count
filePath = targetFiles(i)
savePath = "C:\Work\OutputFiles\" & Mid(filePath, InStrRev(filePath, "\") + 1)
' --- AutoCADセッションの開始 ---
Set acadApp = CreateObject("AutoCAD.Application")
acadApp.Visible = True ' デバッグ時はTrue、本番はFalse推奨
' 2. 図面を開いてWorkerを呼び出す
' ※ ここではCOM経由でAutoCAD内のマクロを叩く
On Error Resume Next
Dim doc As Object
Set doc = acadApp.Documents.Open(filePath)
If Not doc Is Nothing Then
' AutoCAD内のマクロを実行 (コマンドライン経由またはVBScript経由)
' 実際の実装では、acadApp.Run を使用するか、
' 別のスクリプトファイルとして実行させる
Call ExecuteWorkerMacro(acadApp, filePath, savePath)
doc.Close False ' 保存せずに閉じる(Worker側でSaveAs済みのため)
Set doc = Nothing
End If
' 3. AutoCADの完全終了(メモリ解放の要)
acadApp.Quit
Set acadApp = Nothing
' --- ステータス管理 ---
currentBatchCount = currentBatchCount + 1
Debug.Print "Processed: " & i & "/" & targetFiles.Count
' 進捗をExcelシートに記録(チェックポイント機能)
RecordProgress i, filePath, "SUCCESS"
' 4. 定期的なリフレッシュ(バッチサイズに達したら明示的に待機/ログ出力)
If currentBatchCount >= batchSize Then
' OSにメモリを整理する時間をわずかに与える
DoEvents
currentBatchCount = 0
Debug.Print "--- Batch Refresh Completed ---"
End If
Next i
MsgBox "全工程が完了しました。", vbInformation
End Sub
' ※ 実装の詳細は環境に依存するため、概念的なラッパーとして記述
Private Sub ExecuteWorkerMacro(app As Object, fPath As String, sPath As String)
' ここで、AutoCAD内のVBA関数をCOM経由で呼び出す
' 例: app.Run "BatchConvertWorker", fPath, sPath, 2018
End Sub
4. プロフェッショナルとしての「詰め」:設計の注意点
このアーキテクチャを実戦投入する際、以下の3点を必ず考慮せよ。
① チェックポイント(再開機能)の実装
数千枚の処理中、PCの再起動やネットワークの瞬断は必ず起きる。
`RecordProgress` 関数において、「どのファイルまで完了したか」を外部ファイル(CSVやSQLite等)に逐次書き出すことが不可欠だ。Orchestratorは起動時にそのファイルを読み込み、未処理のインデックスからループを開始しなければならない。
② エラーハンドリングの階層化
- Workerレベルのエラー: 特定の図面が壊れている場合、その図面を「スキップ」してOrchestratorに通知し、次の図面へ進む。
- Orchestratorレベルのエラー: AutoCADが応答なし(Not Responding)になった場合、`taskkill` コマンド等を用いてプロセスを強制終了し、プロセスを再生成する「自己修復」ロジックを持つべきだ。
③ ファイルI/Oのオーバーヘッド
大量のファイルを開閉する際、ネットワークドライブへのアクセスはボトルネックになる。可能な限り、「ローカルSSDへのコピー → 処理 → 完了後にネットワークへ戻す」というワークフローを組むことで、スループットは劇的に向上する。
結論
AutoCAD VBAにおける大量処理の極意は、「AutoCADを信じすぎないこと」にある。
一つのプロセスにすべてを委ねるのではなく、プロセスを使い捨て可能な「部品」へと格下げし、それを外部のOrchestratorが統治する。この「分離と制御」の思想こそが、バグの起きない、堅牢な業務自動化ツールを生む唯一の道である。
設計に魂を込めろ。メモリリークは、君の設計の甘さを突いてくる。
