巨大アセンブリ図面生成におけるメモリ・アーキテクチャ:軽量表現と解像度の動的制御
設計現場において、数千、数万のコンポーネントを含む超大規模アセンブリの図面化は、単なる「自動化」の範疇を超えた「リソース管理の戦い」へと変貌する。
多くの開発者が陥る罠がある。それは、`CreateDrawViewFromModelView` を呼び出す際、SolidWorksがモデルをどのようにメモリ上に展開するかを制御せず、OSの仮想メモリとSolidWorksのヒープ領域の限界にすべてを委ねてしまうことだ。その結果、システムはスラッシング(Disk Swapping)を起こし、最終的には `Out of Memory` または応答なしのフリーズへと至る。
本稿では、単にビューを作成するコードではない。Windows APIを用いてプロセスのメモリ圧力を監視し、コンポーネントの「軽量表示(Lightweight)」状態を動的に制御することで、極限までメモリ消費を抑制しつつ、図面の品質(解像度)を担保する、プロフェッショナル向けのアーキテクチャを提示する。
1. 概念的基盤:Lightweight 状態の戦略的運用
SolidWorksにおける「軽量表示(Lightweight)」は、単なる表示モードではない。それは、コンポーネントのフィーチャツリーの大部分をメモリから排出し、ジオメトリの境界ボックスと最小限のグラフィックスデータのみを保持する「低解像度プロキシ」の状態である。
大規模図面生成における黄金律は以下の通りである:
1. Assembly Open: 全コンポーネントを `Lightweight` モードで開く。
2. View Creation: 図面ビューの生成は `Lightweight` 状態で実行する。
3. Selective Resolution: 断面図や詳細図が必要な箇所、あるいは特定の重要部品のみを `Resolved`(完全解決)状態へ昇格させる。
4. Garbage Collection: 各オブジェクトの参照を明示的に破棄し、COMの生存期間を管理する。
2. 実装:メモリ監視と動的制御の統合
以下に、Windows APIを用いたメモリ使用量監視機能を組み込んだ、堅牢な図面生成エンジンのコアロジックを示す。
Option Explicit
' --- Windows API Declarations for Memory Monitoring ---
Private Type PROCESS_MEMORY_COUNTERS
cb As Long
PageFaultCount As Long
PeakWorkingSetSize As LongPtr
WorkingSetSize As LongPtr
QuotaPeakPagedPoolUsage As LongPtr
QuotaPagedPoolUsage As LongPtr
QuotaPeakNonPagedPoolUsage As LongPtr
QuotaNonPagedPoolUsage As LongPtr
PagefileUsage As LongPtr
PeakPagefileUsage As LongPtr
End Type
If VBA7 Then
Private Declare PtrSafe Function GetCurrentProcess Lib "kernel32" () As LongPtr
Private Declare PtrSafe Function GetProcessMemoryInfo Lib "psapi.dll" ( _
ByVal hProcess As LongPtr, _
ByRef lpCounters As PROCESS_MEMORY_COUNTERS, _
ByVal cb As Long) As Long
Else
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function GetProcessMemoryInfo Lib "psapi.dll" ( _
ByVal hProcess As Long, _
ByRef lpCounters As PROCESS_MEMORY_COUNTERS, _
ByVal cb As Long) As Long
End If
' --- Global Constants ---
Private Const MEMORY_THRESHOLD_MB As Long = 8192 ' 8GBを超えたら警告/停止する閾値
''' <summary>
''' 現在のプロセスのWorking Set(物理メモリ使用量)をMB単位で取得する
''' </summary>
Private Function GetCurrentMemoryUsageMB() As Long
Dim counters As PROCESS_MEMORY_COUNTERS
Dim hProcess As LongPtr
Dim ret As Long
hProcess = GetCurrentProcess()
ret = GetProcessMemoryInfo(hProcess, counters, LenB(counters))
If ret <> 0 Then
GetCurrentMemoryUsageMB = counters.WorkingSetSize / 1024 / 1024
Else
GetCurrentMemoryUsageMB = 0
End If
End Function
''' <summary>
''' 大規模アセンブリ図面生成のメインルーチン
''' </summary>
Public Sub GenerateLargeAssemblyDrawing()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
Dim swDraw As SldWorks.DrawingDoc
Dim swView As SldWorks.View
Dim swComp As SldWorks.Component2
Dim vComps As Variant
Dim i As Long
On Error GoTo ErrorHandler
Set swApp = Application.SldWorks
' 1. アセンブリを軽量モードで開く(重要:OpenDoc6の引数で制御)
' ※ここでは既存の開いているモデルを対象とする例
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then Exit Sub
If swModel.GetType <> swDocASSEMBLY Then Exit Sub
Set swAssy = swModel
' 2. メモリ監視開始
Debug.Print "Initial Memory Usage: " & GetCurrentMemoryUsageMB() & " MB"
' 3. 全コンポーネントを強制的にLightweightに設定
' これにより、図面作成時のメモリスパイクを劇的に抑制する
vComps = swAssy.GetComponents(False)
For i = 0 To UBound(vComps)
Set swComp = vComps(i)
' Lightweight状態への移行
swComp.SetLightweight swTrue
Next i
' 4. 新規図面作成
Dim drwTemplate As String
drwTemplate = "C:\Templates\LargeAssembly_Standard.drwdot"
Set swDraw = swApp.NewDocument(drwTemplate, 0, 0, 0)
If swDraw Is Nothing Then
Err.Raise 1001, , "Template not found."
End If
' 5. ビューの配置
' 軽量モードのままビューを作成
Set swView = swDraw.CreateDrawViewFromModelView3(swModel.GetPathName, "*Front", 0.1, 0.1, 0)
If Not swView Is Nothing Then
' 6. 特定のコンポーネントのみを「Resolved」に昇格させる(動的最適化)
' 例えば、中心となる主要部品だけを解像させることで、メモリを節約しつつ精度を保つ
' ここでは例として、最初のコンポーネントのみを対象とする
If UBound(vComps) >= 0 Then
Set swComp = vComps(0)
swComp.SetLightweight False ' Resolved状態へ
Debug.Print "Component " & swComp.Name2 & " resolved."
End If
End If
' 7. メモリチェック
Debug.Print "Post-Processing Memory Usage: " & GetCurrentMemoryUsageMB() & " MB"
If GetCurrentMemoryUsageMB() > MEMORY_THRESHOLD_MB Then
MsgBox "Critical Memory Usage Detected: " & GetCurrentMemoryUsageMB() & " MB. Please optimize or increase RAM.", vbCritical
End If
' --- Cleanup: 明示的なオブジェクト解放 ---
' VBAのGCに頼らず、COM参照を確実に断ち切る
Set swView = Nothing
Set swDraw = Nothing
Set swAssy = Nothing
Set swModel = Nothing
Set swApp = Nothing
MsgBox "Process Completed Successfully.", vbInformation
Exit Sub
ErrorHandler:
MsgBox "Error " & Err.Number & ": " & Err.Description, vbCritical
' エラー時も可能な限り解放を試みる
Set swView = Nothing
Set swDraw = Nothing
Set swAssy = Nothing
Set swModel = Nothing
Set swApp = Nothing
End Sub
3. アーキテクチャの核心:なぜこの手法が「極限」なのか
3.1 Windows APIによる「外からの監視」
VBA内部の変数(`swApp` 等)の状態だけを見ていても、OSレベルでのメモリ圧力を把握することは不可能だ。`GetProcessMemoryInfo` を用いることで、SolidWorksプロセスが物理メモリ(Working Set)をどれだけ食いつぶしているかをリアルタイムに数値化できる。これは、バッチ処理などで長時間稼働させる自動化システムにおいて、プロセスの異常終了を未然に防ぐための「防波堤」となる。
3.2 コンポーネント・ライフサイクルの制御
通常の自動化スクリプトは、アセンブリを開いてそのまま図面を作る。しかし、これではSolidWorksはすべてのフィーチャを計算(Resolve)しようとする。
本コードの肝は、`swComp.SetLightweight swTrue` による強制的なプロキシ化である。図面ビューを作成する際、SolidWorksは軽量モデルのジオメトリのみを使用してビューを構築するため、メモリ消費量は指数関数的に減少する。
3.3 COMオブジェクトの明示的解放
VBAにおいて `Set obj = Nothing` は、単なる慣習ではない。大規模なループ処理や複雑な階層構造を持つオブジェクトを扱う場合、参照カウントが正しく減少しない限り、メモリは解放されない。特に `Component2` や `View` オブジェクトは、背後のC++実装側で巨大なリソースを保持しているため、これらを明示的に `Nothing` にすることは、メモリリークを防ぐための「儀式」ではなく「必須の設計要件」である。
4. 結論
大規模アセンブリの図面自動化における真のエンジニアリングとは、SolidWorksの機能を使いこなすことだけではない。OSのリソース、COMの参照カウント、そしてメモリの動的な振る舞いを予測し、制御することにある。
「動けばいい」というコードは、小規模なテスト環境では通用する。しかし、数千人のエンジニアが利用する社内標準システムや、数万点の部品を扱うプロダクト開発の現場では、こうした「メモリ・アーキテクチャ」への深い理解が、システムの信頼性を決定づけるのだ。
