SolidWorks夜間バッチの死神を葬る:メモリリークと戦うアーキテクトの流儀
数千個のパーツを生成し、幾何公差を付与し、PDF/STEPを出力して保存する。この単純なルーチンを何百時間も安定して回し続けるシステムを設計する時、多くのエンジニアは「VBAの記述」にしか関心を持たない。
だが、現実は冷酷だ。SolidWorksのCOMインターフェースは、メモリ管理という名の地雷原である。数千回繰り返される`SelectByID2`、蓄積される選択バッファ、解放されないCOMオブジェクト。これらは確実にSolidWorksのワークセットを汚染し、夜間のバッチ処理を「沈黙のフリーズ」という名の墓場へ引きずり込む。
今回は、数万のパーツ生成を完遂するために必要な「真のメモリ管理」について語る。
—
1. 選択バッファの呪縛:`ClearSelection2`の真実
多くの初学者は、「`ClearSelection2(True)`を呼べば安心」だと信じている。しかし、大規模バッチ処理において、これは半分正解で半分無知だ。
SolidWorksの選択リストは、単なる選択状態の保持ではない。それはオブジェクトの参照を保持し、再描画のキュー(通知)を生成する。このキューが溜まると、GC(ガベージコレクション)が追いつかなくなる。
究極の選択解除ルーチン
‘ 選択バッファを完全にフラッシュし、描画負荷を最小化する
Public Sub SafeClearSelection(ByRef swModel As SldWorks.ModelDoc2)
‘ Trueを渡すことで、選択解除の通知を抑止しパフォーマンスを向上させる
‘ 頻繁な選択操作を行うループ内では、これを呼ぶタイミングが全てを決める
swModel.ClearSelection2 True
‘ 重要: インターフェースの整合性を担保するため、
‘ 複雑なジオメトリ操作の直後にはDoEventsを挟み、メッセージキューを処理させる
DoEvents
End Sub
—
2. `UserControl`プロパティが救うもの
SolidWorksをAPI経由で操作する場合、プロセスは外部から制御されるため、`swApp.UserControl = False`の状態になることが多い。この状態はメモリ管理の観点からは諸刃の剣だ。
`UserControl = False`のまま大量のドキュメントを生成すると、SolidWorksは「これはバックグラウンドの無人プロセスである」と解釈し、リソースの開放優先度を下げる傾向がある。これを逆手に取り、適切なタイミングで「UI制御権」を一時的にOSのメッセージループへ返却する必要がある。
—
3. 実践:メモリリークを根絶するパーツ生成テンプレート
以下のコードは、数千個のループを回してもメモリ使用量をフラットに保つための、アーキテクチャの雛形である。
‘ メモリリークを防止するパーツ生成の定石
Public Sub ExecuteMassGeneration(ByVal count As Long)
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim i As Long
Set swApp = Application.SldWorks
‘ バッチ中はユーザー操作を遮断し、描画をオフにする
swApp.Visible = True ‘ プロセス生存確認
swApp.UserControl = False
For i = 1 To count
‘ 1. モデル生成
Set swModel = swApp.NewDocument(“Part”, 0, 0, 0)
‘ 2. フィーチャ操作(ここでは割愛)
‘ 3. 選択解除の徹底
SafeClearSelection swModel
‘ 4. オブジェクトの明示的破棄(重要)
‘ COM参照を即座に開放し、参照カウントをゼロにする
swApp.CloseDoc swModel.GetTitle
Set swModel = Nothing
‘ 5. メモリのフラッシュ(OSのメッセージループを回す)
‘ 大規模ループの節目で強制的なGC/COM参照開放を促す
If i Mod 10 = 0 Then
Debug.Print “Cleaning memory at index: ” & i
DoEvents
End If
Next i
‘ 終了処理
swApp.UserControl = True
End Sub
—
4. 伝説的エンジニアからの提言:なぜ落ちるのか
メモリリークの原因は、VBAコードそのものよりも「COMオブジェクトの不適切な参照保持」にある。
- `DoEvents`の魔法: VBAはシングルスレッドであり、メッセージループを放置するとWindowsはSolidWorksを「応答なし」と判定し、強制終了させる可能性がある。`DoEvents`は単なる待機ではなく、OSとの対話を維持し、メモリの再配置を許可する重要な儀式だ。
- オブジェクトのスコープ: `Set swModel = Nothing`を怠ることは、C++で`delete`を忘れることと同義である。特にループ内で生成された一時的な`Feature`や`Entity`オブジェクトは、必ずループごとに`Nothing`を代入せよ。
- Windows APIの活用: 数時間単位のバッチであれば、`GlobalMemoryStatusEx`などのWin32 APIを呼び出し、プロセス全体のメモリ占有率を監視するウォッチドッグを別プロセスで走らせるのも手だ。異常な上昇を検知したら、現在の処理を安全に終了(シリアライズ)し、SolidWorksプロセスごと再起動させる。
結論
大規模バッチの安定化とは、「SolidWorksをいかにして正常な状態で使い捨て続けるか」という哲学に他ならない。
メモリを大切に扱うのではない。メモリが汚れることを前提とし、その汚染を定期的かつ強制的にクリアする。これが、伝説的なシステムを構築する者の唯一の正解だ。
コードを書くときは、常にその背後に「数万回の反復」という重みを意識しろ。それが、君をただのVBA職人から、本物の自動化エンジニアへと昇華させる。
