Pergunta

Eu li um monte de artigos na net sobre a liberação de RCW de segurança, e parece-me que ninguém pode concordar sobre o que exatamente precisa ser feito em que ordem, por isso estou pedindo a vocês por suas opiniões. Por exemplo, pode-se fazer isso:

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

No entanto, algumas pessoas defendem fazendo a coleta de lixo antes Marshal.FinalReleaseComObject, alguns depois, e alguns não em todos. É realmente necessário para GC cada RCW manualmente, especialmente depois que ele já foi separada de seu objeto COM?

Para mim, seria mais simples e mais fácil simplesmente retirar o RCW do objeto COM e deixar o RCW para expirar naturalmente:

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

É suficiente para fazer isso?

Foi útil?

Solução

Para ter sua referência ao objeto de destino COM lançado, é suficiente e preferiu para Marshal.FinalReleaseComObject chamada justa e não forçar uma coleta. Em outras palavras, você se encontrou com sua responsabilidade para liberar sua referência assim que foram feito com ele. Eu não vou tocar na questão da FinalReleaseComObject vs ReleaseComObject.

Isso deixa a maior questão de por que as pessoas defendem chamando GC.Collect() e WaitForPendingFinalizers()?

Porque para alguns projetos, é difícil saber quando não há mais referências gerenciadas de modo que você não pode chamar com segurança ReleaseComObject. Você tem duas opções, permitem a construção de memória para cima e espero que a coleta acontece ou forçar uma coleta. [Ver nota abaixo votação de Steven Jansen no comments]

Uma nota adicional é que a criação target para null é geralmente desnecessário, e, especificamente, é desnecessário em seu código de amostra. Configurando objetos para nada é prática comum para VB6 uma vez que utiliza um coletor de lixo baseado contagem de referência. O compilador de C # é o suficiente inteligente (quando a construção para a liberação) para saber que target está inacessível após a sua última utilização e poderia ser GC'd, mesmo antes de sair do escopo. E por último uso, quero dizer último uso possível de forma que há casos em que você pode configurá-lo para null. Você pode ver isso por si mesmo com o código abaixo:

   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 você construir liberação (por exemplo, CSC GCTest.cs), "finalizados" irá imprimir entre "Olá" e "adeus". Se você construir depuração (por exemplo, CSC / GCTest.cs depuração), "finalizados" irá imprimir depois de "bye", enquanto definição x como nulo antes de Collect() teria "fixo" que.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top