まず、Excel の相互運用を行うときに、または呼び出す必要はありません。これは紛らわしいアンチパターンですが、.NET から手動で COM 参照を解放する必要があることを示す Microsoft からの情報を含め、これに関する情報は正しくありません。実際、.NET ランタイムとガベージ コレクターは、COM 参照を正しく追跡してクリーンアップします。Marshal.ReleaseComObject(...)
Marshal.FinalReleaseComObject(...)
次に、アウト プロセス COM オブジェクトへの COM 参照がプロセスの終了時に確実にクリーンアップされるようにする (Excel プロセスが終了するようにする) 場合は、ガベージ コレクターが実行されていることを確認する必要があります。と の呼び出しでこれを正しく行いGC.Collect()
ますGC.WaitForPendingFinalizers()
。2 回呼び出しても安全です。end を使用すると、サイクルも確実にクリーンアップされます。
第 3 に、デバッガーで実行している場合、ローカル参照はメソッドの最後まで人工的に保持されます (ローカル変数の検査が機能するようにするため)。したがって、呼び出しは、同じメソッドからのGC.Collect()
ようにオブジェクトをクリーニングするのには効果的ではありません。rng.Cells
GC クリーンアップからの COM 相互運用を実行するコードを別のメソッドに分割する必要があります。
一般的なパターンは次のとおりです。
Sub WrapperThatCleansUp()
' NOTE: Don't call Excel objects in here...
' Debugger would keep alive until end, preventing GC cleanup
' Call a separate function that talks to Excel
DoTheWork()
' Now Let the GC clean up (twice, to clean up cycles too)
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
Sub DoTheWork()
Dim app As New Microsoft.Office.Interop.Excel.Application
Dim book As Microsoft.Office.Interop.Excel.Workbook = app.Workbooks.Add()
Dim worksheet As Microsoft.Office.Interop.Excel.Worksheet = book.Worksheets("Sheet1")
app.Visible = True
For i As Integer = 1 To 10
worksheet.Cells.Range("A" & i).Value = "Hello"
Next
book.Save()
book.Close()
app.Quit()
' NOTE: No calls the Marshal.ReleaseComObject() are ever needed
End Sub
MSDN や StackOverflow の多くの投稿を含め、この問題については多くの誤った情報と混乱があります。
最終的に私が詳しく調べて適切なアドバイスを見つけ出すように説得したのは、この投稿https://blogs.msdn.microsoft.com/visualstudio/2010/03/01/marshal-releasecomobject-considered-dangerous/と一緒に一部の StackOverflow 回答で、デバッガーの下で参照が維持される問題。