Question

J'ai lu beaucoup d'articles sur le net à propos de la libération RCW de sécurité, et il me semble que personne ne peut se mettre d'accord sur exactement ce qui doit être fait dans quel ordre, donc je vous demande les gars pour vos opinions. Par exemple, on pourrait faire ceci:

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

Cependant, certaines personnes préconisent de faire la collecte des ordures avant Marshal.FinalReleaseComObject, certains après, et d'autres pas du tout. Est-il vraiment nécessaire de GC chaque RCW manuellement, surtout après qu'il a déjà été détaché de son objet COM?

A mon avis, il serait plus simple et plus facile de détacher le RCW de l'objet COM et laisser le RCW expirer naturellement:

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

Est-il suffisant pour le faire?

Était-ce utile?

La solution

Pour que votre référence à l'objet COM cible libéré, il suffit et préféré pour appeler juste Marshal.FinalReleaseComObject et pas forcer Collect. En d'autres termes, vous avez rencontré votre responsabilité de libérer votre référence dès que vous avez été fait avec elle. Je ne vais pas toucher la question de FinalReleaseComObject vs ReleaseComObject.

Cela laisse la plus grande question de savoir pourquoi les gens préconisent d'appeler GC.Collect() et WaitForPendingFinalizers()?

Parce que pour certains modèles, il est difficile de savoir quand il n'y a pas de références plus gérées de sorte que vous ne pouvez pas appeler en toute sécurité ReleaseComObject. Vous avez deux choix, laissez la mémoire construire et nous espérons un Collect arrive ou forcer un Collect. [Voir vote down Steven Jansen note dans les commentaires]

Une note supplémentaire est que la mise en target à null est généralement inutile, et est spécifiquement inutile dans votre exemple de code. objets Réglage rien est pratique courante pour VB6 car il utilise un collecteur de déchets à base de comptage de référence. Le compilateur C # est assez intelligent (lors de la construction pour la libération) de savoir que target est injoignable après sa dernière utilisation et pourrait être GC'd, même avant de quitter la portée. Et dernière utilisation, je veux dire la dernière utilisation possible donc il y a des cas où vous pouvez définir à null. Vous pouvez voir par vous-même avec le code ci-dessous:

   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 vous construisez la libération (par exemple, le SCC GCTest.cs), « Finalisé » imprimera entre « bonjour » et « au revoir ». Si vous construisez debug (par exemple, GCTest.cs CSC / debug), « Finalisé » sera imprimé après « bye », alors que la mise en x à null avant Collect() aurait « fixe » que.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top