私もこの質問を調査しており、COM/.Net-Interop 中心のアプリケーションに取り組み、リーク、ハング、クラッシュと戦っています。
簡単な答え: COM オブジェクトが COM 環境から .NET に渡されるたびに。
長い答え:
- 各 COM オブジェクトに対して 1 つの RCW オブジェクトがあります [テスト 1] [参照 4]
- COM オブジェクト内からオブジェクトが要求されるたびに参照カウントがインクリメントされる (COM オブジェクトを返す COM オブジェクトのプロパティまたはメソッドを呼び出すと、返される COM オブジェクトの参照カウントが 1 つインクリメントされる) [テスト 1]
- オブジェクトの他の COM インターフェイスにキャストしたり、RCW 参照を移動したりしても、参照カウントがインクリメントされない [テスト 2]
- COM によって発生したイベントでオブジェクトがパラメーターとして渡されるたびに、参照カウントがインクリメントされます [参照 1]
補足: COM オブジェクトは、使い終わったらすぐに解放する必要があります。この作業を GC に任せると、リーク、予期しない動作、およびイベントのデッドロックが発生する可能性があります。オブジェクトが作成された STA スレッド以外でオブジェクトにアクセスする場合、これは 10 倍重要になります。[参照 2] [参照 3] [つらい個人的な経験]
すべてのケースをカバーできたことを願っていますが、COM は難しいクッキーです。乾杯。
テスト 1 - 参照カウント
private void Test1( _Application outlookApp )
{
var explorer1 = outlookApp.ActiveExplorer();
var count1 = Marshal.ReleaseComObject(explorer1);
MessageBox.Show("Count 1:" + count1);
var explorer2 = outlookApp.ActiveExplorer();
var explorer3 = outlookApp.ActiveExplorer();
var explorer4 = outlookApp.ActiveExplorer();
var equals = explorer2 == explorer3 && ReferenceEquals(explorer2, explorer4);
var count2 = Marshal.ReleaseComObject(explorer4);
MessageBox.Show("Count 2:" + count2 + ", Equals: " + equals);
}
Output:
Count 1: 4
Count 2: 6, Equals: True
テスト 2 - 参照カウントの続き。
private static void Test2(_Application outlookApp)
{
var explorer1 = outlookApp.ActiveExplorer();
var count1 = Marshal.ReleaseComObject(explorer1);
MessageBox.Show("Count 1:" + count1);
var explorer2 = outlookApp.ActiveExplorer();
var explorer3 = explorer2 as _Explorer;
var explorer4 = (ExplorerEvents_10_Event)explorer2;
var explorerObject = (object)explorer2;
var explorer5 = (Explorer)explorerObject;
var equals = explorer2 == explorer3 && ReferenceEquals(explorer2, explorer5);
var count2 = Marshal.ReleaseComObject(explorer4);
MessageBox.Show("Count 2:" + count2 + ", Equals: " + equals);
}
Output:
Count 1: 4
Count 2: 4, Equals: True
私の経験とテストに加えて、私が中継している情報源:
1. Johannes Passing's - RCW Reference Counting Rules != COM Reference Counting Rules
2. Eran Sandler - ランタイム呼び出し可能ラッパーの内部構造とよくある落とし穴
3. Eran Sandler - Marshal.ReleaseComObject と CPU の回転
4. MSDN - ランタイム呼び出し可能ラッパー