Domanda

Ho letto un sacco di articoli in rete di rilasciare RCW di sicurezza, e mi sembra che nessuno può essere d'accordo su esattamente ciò che deve essere fatto in quale ordine, quindi vi chiedo ragazzi per le vostre opinioni. Ad esempio, si potrebbe fare questo:

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

Tuttavia, alcune persone avvocato facendo la raccolta dei rifiuti, prima Marshal.FinalReleaseComObject, alcuni dopo, e alcuni non a tutti. E 'davvero necessario per GC ogni singolo RCW manualmente, soprattutto dopo che è già stato distaccato dal suo oggetto COM?

A mio avviso, sarebbe più semplice e più facile da staccare solo l'RCW dall'oggetto COM e lasciare il RCW per scadere naturale:

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

E 'sufficiente per farlo?

È stato utile?

Soluzione

Per avere il vostro riferimento all'oggetto di destinazione COM rilasciato, è sufficiente e preferito per chiamare solo Marshal.FinalReleaseComObject e non forzare una raccolta. In altre parole, avete incontrato la vostra responsabilità di liberare il vostro riferimento, non appena avessi finito con esso. Non toccherò la questione della FinalReleaseComObject vs ReleaseComObject.

Questo lascia la grande questione del perché la gente avvocato chiamando GC.Collect() e WaitForPendingFinalizers()?

Perché per alcuni disegni, è difficile sapere quando non ci sono riferimenti più gestiti in modo non è possibile chiamare in modo sicuro ReleaseComObject. Hai due scelte, lascia che la memoria di costruire e la speranza di una raccolta accade o forzare una raccolta. [Vedere giù nota voto di Steven Jansen nei commenti]

Una nota aggiuntiva è che l'impostazione target a null di solito è inutile, e in particolare non è necessaria nel codice di esempio. Impostazione oggetti per nulla è pratica comune per VB6 poiché usa un garbage collector basato conteggio di riferimento. Il compilatore per C # è abbastanza intelligente (quando si costruisce per il rilascio) di sapere che target non è raggiungibile dopo il suo ultimo utilizzo e potrebbe essere GC'd, anche prima di lasciare campo di applicazione. E per ultimo utilizzo, voglio dire l'ultima uso possibile quindi non ci sono casi in cui si potrebbe impostare a null. Si può vedere questo per te stesso con il codice qui sotto:

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

Se si costruisce rilascio (per esempio, CSC GCTest.cs), "finalizzato" stamperà tra "ciao" e "arrivederci". Se si crea il debug (ad esempio, GCTest.cs CSC / di debug), "finalizzato" stamperà dopo "bye", mentre l'impostazione x su null prima Collect() sarebbe "fisso" che.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top