2009-06-04 13 views
12

COMオブジェクトには通常、確定的な破壊があります。これらのオブジェクトは、最後の参照が解放されたときに解放されます。C#+ COM相互運用性、確定的なリリース

これはC# - COM Interopでどのように処理されますか?クラスはIDisposableを実装していないので、明示的なIUnknown :: Releaseを起動する方法はありません。

カジュアルテストでは、参照されていないCOMオブジェクトが遅れて収集されていることがわかります(ガベージコレクターがリリースをトリガーしています)。積極的にリリースする必要のあるOCMオブジェクトではどうすればよいですか? (例えば、大規模または共有のクリティカルなリソースを保持する)?

元の問題:私たちは、COMライブラリを大量に使用しているC#アプリケーションを持っていて、それは気になるように漏れています。問題はC++コードとC#コードの間にあると思われますが(両方にアクセスできます)、問題は解決できません。

答えて

16

System.Runtime.InteropServices.Marshalクラスを使用してCOM相互参照を操作できます。具体的には、Marshal.ReleaseComObjectをご覧ください。

+2

1:単一放出を可能にする -

は、ここで、各ノードに値を取り込み、私たちの意図を議論するExpression木を使用し続けています。 – OregonGhost

5

これはかなり苦しんでいます。 .Netランタイムにあまりにも多くのinterop参照をロードしようとしないことをお勧めします。また、すぐに何かをリリースする必要がある場合は、Marshal.ReleaseComObject APIを使用することもできます。

もう一つの良い方法は、相互運用コードの周りにタイプセーフラッパーを使用するようにクライアントコードをリファクタリングすることです - あなたは一人ひとりの相互運用RCWにあなたのコード内の既知の基準を持っている場合、これは相互運用参照にGCedになる確率が高くなり時機を得た方法。 (おそらくない本当に長い目で)私たちが持っているので、上記のコードでは、ドット間の各オブジェクトを効果的にリークされ

foo.bar.quux.xyzzy.groo(); // where foo, bar, quux and xyzzy are all COM references 

:これは避けるように努め主な問題は、「あまりにも多くのドット」の一つでありますインスタンスへの暗黙の参照あなたはそれらをクリーンアップするための良い機会を持っているために、各インスタンスに名前の参照を作成する必要があります:

Foo foo; 
Bar bar=foo.bar; 
Quux quux=bar.quux; 
Xyzzy xyzzy=quux.xyzzy; 
xyzzy.groo(); 

今おそらく参照を解放するためにランタイムを使用します。

ReleaseComObject(xyzzy); // etc... 
2

これは、 related (but subtly different) questionから、私は答えがきちんと整っていると思うので、私はそれもここに追加することを正当化すると思った。これは何度も私の人生は、より保存されているので、

static class ComExample { 
    static void Main() 
    { 
     using (var wrapper = new ReleaseWrapper()) 
     { 
      var baz = wrapper.Add(() => new Foo().Bar.Baz); 
      Console.WriteLine(baz.Name); 
     } 
    } 
} 
class ReleaseWrapper : IDisposable 
{ 
    List<object> objects = new List<object>(); 
    public T Add<T>(Expression<Func<T>> func) 
    { 
     return (T)Walk(func.Body); 
    } 
    object Walk(Expression expr) 
    { 
     object obj = WalkImpl(expr); 
     if (obj != null && Marshal.IsComObject(obj) 
       && !objects.Contains(obj)) { objects.Add(obj); } 
     return obj; 
    } 
    object WalkImpl(Expression expr) 
    { 
     switch (expr.NodeType) 
     { 
      case ExpressionType.Constant: 
       return ((ConstantExpression)expr).Value; 
      case ExpressionType.New: 
       NewExpression ne = (NewExpression)expr; 
       object[] args = ne.Arguments.Select(arg => Walk(arg)).ToArray(); 
       return ne.Constructor.Invoke(args); 
      case ExpressionType.MemberAccess: 
       MemberExpression me = (MemberExpression)expr; 
       object target = Walk(me.Expression); 
       switch (me.Member.MemberType) 
       { 
        case MemberTypes.Field: 
         return ((FieldInfo)me.Member).GetValue(target); 
        case MemberTypes.Property: 
         return ((PropertyInfo)me.Member).GetValue(target, null); 
        default: 
         throw new NotSupportedException(); 

       } 
      default: 
       throw new NotSupportedException(); 
     } 
    } 
    public void Dispose() 
    { 
     foreach(object obj in objects) { 
      Marshal.ReleaseComObject(obj); 
      Debug.WriteLine("Released: " + obj); 
     } 
     objects.Clear(); 
    } 
}