Выпуск ссылки COM-объекта безопасно от.NET

Я прочитал много статей о сети о выпуске RCW безопасно, и мне кажется, что никто не может договориться точно, какие потребности быть выполненным, что порядок, таким образом, я прошу у Вас парни Ваши мнения. Например, можно было сделать это:

object target = null;
try {
    // Instantiate and use the target object.
    // Assume we know what we are doing: the contents of this try block
    // do in fact represent the entire desired lifetime of the COM object,
    // and we are releasing all RCWs in reverse order of acquisition.
} finally {
    if(target != null) {
        Marshal.FinalReleaseComObject(target);
        target = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

Однако некоторые люди рекомендуют делать сборку "мусора" прежде Marshal.FinalReleaseComObject, некоторые после и некоторые нисколько. Это действительно необходимо для GC каждый RCW вручную, особенно после того, как это было уже отсоединено от его COM-объекта?

По моему мнению это было бы более просто и легко, чтобы просто отсоединить RCW от COM-объекта и оставить RCW для истечения естественно:

object target = null;
try {
    // Same content as above.
} finally {
    if(target != null) {
        Marshal.FinalReleaseComObject(target);
    }
}

Действительно ли достаточно сделать это?

6
задан Christian Hayter 3 December 2009 в 20:39
поделиться

1 ответ

To have your reference to the target COM object released, it is sufficient and preferred to just call Marshal.FinalReleaseComObject and not force a collect. In other words, you've met your responsibility to release your reference as soon as you were done with it. I won't touch the issue of FinalReleaseComObject vs ReleaseComObject.

This leaves the bigger question of why do people advocate calling GC.Collect() and WaitForPendingFinalizers()?

Because for some designs, it's hard to know when there are no more managed references so you can't safely call ReleaseComObject. You have two choices, let the memory build up and hope a collect happens or force a collect. [see Steven Jansen's down vote note in the comments]

An additional note is that setting target to null is usually unnecessary, and specifically is unnecessary in your sample code. Setting objects to nothing is common practice for VB6 since it uses a reference count based garbage collector. The compiler for C# is clever enough (when building for release) to know that target is unreachable after its last use and could be GC'd, even before leaving scope. And by last use, I mean last possible use so there are cases where you might set it to null. You can see this for yourself with the code below:

   using System;
   class GCTest
   {
       ~GCTest() { Console.WriteLine("Finalized"); } 
       static void Main()
       {
           Console.WriteLine("hello");
           GCTest x = new GCTest();
           GC.Collect();
           GC.WaitForPendingFinalizers();
           Console.WriteLine("bye");
       }
   }

If you build release (e.g., CSC GCTest.cs), "Finalized" will print out between "hello" and "bye". If you build debug (e.g., CSC /debug GCTest.cs), "Finalized" will print out after "bye" whereas setting x to null prior to Collect() would have "fixed" that.

12
ответ дан 9 December 2019 в 20:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: