Pregunta

He leído un montón de artículos en la red sobre la liberación de RCW de forma segura, y me parece que nadie puede ponerse de acuerdo sobre exactamente lo que hay que hacer y en qué orden, por lo que te pido chicos por sus opiniones. Por ejemplo, se podría hacer esto:

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();
    }
}

Sin embargo, algunas personas abogan por hacer la recolección de basura antes de Marshal.FinalReleaseComObject, algunos después, y algunos no en todos. ¿Es realmente necesario a GC cada RCW manualmente, sobre todo después de que ya se ha separado de su objeto COM?

A mi entender, sería más simple y más fácil simplemente separar la RCW desde el objeto COM y dejar el RCW expirar natural:

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

¿Es suficiente para hacer eso?

¿Fue útil?

Solución

Para que su referencia al objeto COM objetivo puesto en libertad, que es suficiente y preferido para llamar simplemente Marshal.FinalReleaseComObject y no forzar un cobro revertido. En otras palabras, que haya cumplido su responsabilidad para liberar su referencia tan pronto como se les terminado con él. No voy a tocar el tema de la FinalReleaseComObject vs ReleaseComObject.

Esto deja a la gran pregunta de por qué la gente abogan llamar GC.Collect() y WaitForPendingFinalizers()?

Debido a que para algunos diseños, es difícil saber cuando ya no hay más referencias gestionadas por lo que no se puede llamar ReleaseComObject segura. Usted tiene dos opciones, dejar que la memoria se acumulan y espero que suceda una colecta o forzar un cobro revertido. [Ver nota abajo voto de Steven Jansen en los comentarios]

Una nota adicional es que la fijación de target a null suele ser innecesaria, y en concreto no es necesaria en el código de ejemplo. Configuración de objetos para nada es una práctica común para VB6 ya que utiliza un recolector de basura basado contador de referencia. El compilador de C # es lo suficientemente inteligente (cuando se construye para la liberación) para saber que target es inalcanzable después de su último uso y podría ser GC'd, incluso antes de salir de su alcance. Y por último uso, me refiero a la última utilización posible de modo que hay casos donde es posible configurarlo para que null. Esto se puede ver por sí mismo con el siguiente código:

   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");
       }
   }

Si se construye de liberación (por ejemplo, CSC GCTest.cs), "Finalizado" se imprimirá entre "hola" y "adiós". Si se construye de depuración (por ejemplo, GCTest.cs CSC / depuración), "Finalizado" se imprimirá después de "adiós", mientras que el establecimiento de x en null antes de Collect() habría "fijo" que.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top