2009-12-02 9 views
6

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 Les estoy pidiendo sus opiniones. Por ejemplo, se podría hacer esto:El lanzamiento de una referencia a un objeto COM con seguridad de .NET

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 GC cada RCW manualmente, especialmente después de que ya se haya separado de su objeto COM?

En mi opinión, 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?

Respuesta

12

para tener su referencia al objeto COM objetivo puesto en libertad, que es suficiente y preferida a llamarlo a Marshal.FinalReleaseComObject y no forzar un cobro revertido. En otras palabras, ha cumplido con su responsabilidad de publicar su referencia tan pronto como haya terminado con ella. No tocaré el problema de FinalReleaseComObject contra ReleaseComObject.

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

Porque para algunos diseños, es difícil saber cuando ya no hay más referencias gestionadas por lo que no se puede llamar de forma segura ReleaseComObject. Tienes dos opciones: dejar que la memoria se acumule y esperar que suceda un cobro o forzar un cobro. [consulte la nota de votación de Steven Jansen en los comentarios]

Una nota adicional es que la configuración de target a generalmente no es necesaria, y específicamente no es necesaria en el código de muestra. Establecer objetos a cero es una práctica común para VB6 ya que utiliza un recolector de basura basado en conteo de referencia. El compilador de C# es lo suficientemente inteligente (cuando se compila para su lanzamiento) como para saber que target es inalcanzable después de su último uso y podría ser GC'd, incluso antes de abandonar el alcance. Y por último uso, me refiero al último uso posible, por lo que hay casos en los que puede establecerlo en null. Esto se puede ver por sí mismo con el código de abajo:

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 a null antes de Collect() tendría "fijo" que.

+0

Análisis excelente y detallado, gracias Tony! –

+0

Downvote: todas estas personas recomiendan lo opuesto a favor de 'GC.Collect': [un distinguido ingeniero de Microsoft] (http://blogs.msdn.com/b/cbrumme/archive/2003/04/16/51355. aspx), [el equipo de Visual Studio] (http://blogs.msdn.com/b/visualstudio/archive/2010/03/01/marshal-releasecomobject-considered-dangerous.aspx), y [a SO miembro de alto rango ] (http://stackoverflow.com/a/17131389/1995977) –

+0

@Steve: Gracias por los enlaces. He actualizado la respuesta para incluir una referencia a tus advertencias. –

Cuestiones relacionadas