20

アプリケーションを終了していくつかの COM オブジェクトを解放しようとすると、デバッガーで警告が表示されることがあります。

RaceOnRCWCleanUp検出されました

COM オブジェクトを使用するクラスを作成した場合、適切に解放するためにそれらを実装IDisposableして呼び出す必要がありますか?Marshal.FinalReleaseComObjectIDisposable.Dispose

が手動で呼び出されない場合Dispose、ファイナライザーでそれらを解放する必要がありますか、それとも GC が自動的に解放しますか? 今、ファイナライザーを呼び出しDispose(false)ていますが、これが正しいかどうか疑問に思います。

私が使用する COM オブジェクトには、クラスがリッスンするイベント ハンドラーもあります。どうやらイベントは別のスレッドで発生しているようですが、クラスを破棄するときにイベントが発生した場合、どうすれば正しく処理できますか?

4

3 に答える 3

18

まず、Excel の相互運用を行うときに、または呼び出す必要はありません。これは紛らわしいアンチパターンですが、.NET から手動で COM 参照を解放する必要があることを示す Microsoft からの情報を含め、これに関する情報は正しくありません。実際、.NET ランタイムとガベージ コレクターは、COM 参照を正しく追跡してクリーンアップします。Marshal.ReleaseComObject(...)Marshal.FinalReleaseComObject(...)

次に、アウト プロセス COM オブジェクトへの COM 参照がプロセスの終了時に確実にクリーンアップされるようにする (Excel プロセスが終了するようにする) 場合は、ガベージ コレクターが実行されていることを確認する必要があります。と の呼び出しでこれを正しく行いGC.Collect()ますGC.WaitForPendingFinalizers()。2 回呼び出しても安全です。end を使用すると、サイクルも確実にクリーンアップされます。

第 3 に、デバッガーで実行している場合、ローカル参照はメソッドの最後まで人工的に保持されます (ローカル変数の検査が機能するようにするため)。したがって、呼び出しは、同じメソッドからのGC.Collect()ようにオブジェクトをクリーニングするのには効果的ではありません。rng.CellsGC クリーンアップからの 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 回答で、デバッガーの下で参照が維持される問題。

于 2016-06-29T22:33:49.700 に答える