C# - Garbage Collection, Dipose e Finalize


 Neste artigo vamos tratar do garbage collector e mostrar como funcionam os métodos Dispose e Finalize usados para liberar o espaço alocado pelos objetos.

O coletor de lixo (garbage Collector) do .NET Framework gerencia a alocação e liberação de memória para sua aplicação. Cada vez que você cria um novo objeto, o Common Language Runtime aloca memória para o objeto a partir do heap gerenciado. Enquanto os espaços de endereços estão disponíveis no heap gerenciado, o runtime continua a alocar espaço para novos objetos.

Nota: Quando você iniciar um novo processo, o runtime reserva uma região contígua de espaço de endereço para o processo. Este espaço de endereço reservado é chamado de heap gerenciado.

No entanto, a memória não é infinita. Eventualmente, o coletor de lixo deve executar uma coleta, a fim de liberar memória. O motor de otimização do coletor de lixo determina o melhor momento para realizar a coleta, com base nas alocações feitas.

Quando o coletor de lixo executa uma coleta, ele verifica se há objetos no heap gerenciado que não estão mais sendo usados pelo aplicativo e executa as operações necessárias para recuperar sua memória.

Assim, a  coleta de lixo é um processo que libera automaticamente a memória de objetos que não mais estão em uso. A decisão de recorrer ao processo de destruição é feita por um programa especial conhecido como coletor de lixo (Garbage Collector). No entanto, quando um objeto perde o escopo no final do método Main(), o processo de destruição não é necessariamente invocado.

Assim, você não pode determinar quando o método destruidor será chamado. O coletor de lixo também identifica os objetos que não são mais referenciados no programa e libera a memória alocada para eles. Você não pode destruir um objeto explicitamente no código. Na verdade, isso é uma prerrogativa do coletor de lixo, que destrói os objetos para os programadores. O processo de coleta de lixo acontece automaticamente. Ele garante que:

· Objetos são destruídos: Ele não especifica quando o objeto será destruído.
· Apenas os objetos não utilizados são destruídos: um objeto nunca é destruído se ele mantém a referência de um outro objeto.


A linguagem C# fornece métodos especiais que são usados​para liberar a instância de uma classe a partir da memória, são eles :
Finalize() e Dispose().

Finalize()

O método destruidor Finalize() é um método especial que é chamado a partir de uma classe para qual ele pertence ou a partir de classes derivadas. Ele é chamado depois da última referência de um objeto ser liberada da memória.

A plataforma .NET executa automaticamente o destruidor Finalize para destruir os objetos na memória. É importante lembrar porém que este método não pode ser executado imediatamente quando um objeto perde o escopo, pois o Commom Languagem Runtime  (CLR) chama o destruidor Finalize() utilizando um sistema chamado de coleta de lixo de rastreamento de referência na qual a CLR verifica periodicamente os objetos que não estão sendo usados na aplicação. Quando um objeto é encontrado o método Finalize() é chamado e o coletor de lixo libera o objeto da memória.

Mas atenção, o método Finalize não pode ser chamado explicitamente no código. Só o coletor de lixo pode chamar o Finalize quando os objetos se tornam inacessíveis.  

O método Finalize usa muitos recursos do sistema e não limpa a memória imediatamente, ele também não pode ser aplicado diretamente, só pode ser implementado via declaração do destruidor. A seguir temos um exemplo de como declarar o método. É recomendável implementar os métodos Finalize e Dispose em conjunto, se você precisar implementar o método Finalize. Após a compilação o destruidor se torna o método Finalize.

using System;
namespace Finalize_Dispose
{
    public class MinhaClasse : IDisposable
    {
        //Construtor
        public MinhaClasse()
        {//inicialização
        }

        //Destruidor também chamado Finalize
        ~MinhaClasse()
        {
           this.Dispose();
        }
        public void Dispose()
        {
           //código para liberar os recursos não gerenciados
        }
    }
}

Então, quando a implementar Finalize?

Pode ser durante a utilização de qualquer recurso não gerenciado como um Stream de arquivo declarado no nível de classe. Podemos não estar sabendo em que fase ou etapa deve ser apropriada para fechar o arquivo. Este objeto está sendo usado em muitos lugares no aplicativo. Portanto, neste cenário o Finalize pode ser apropriado onde o recurso não gerenciado pode ser liberado.

Dispose()

O método Dispose() é chamado para liberar recursos, como a conexão com um banco de dados, tão logo o objeto usando o recurso não esta mais sendo usado. Diferente do método Finalize() o método Dispose() não é chamado automaticamente e você precisa chamá-lo explicitamente  a partir de uma aplicação cliente quando um objeto não mais for necessário.  A interface IDisposable contém o método Dispose e por isso para chamar este método a classe precisa implementar esta interface.

Há alguns recursos que GC não é capaz de liberar uma vez que não dispõe de informações para reivindicar a memória desses recursos como manipuladores de arquivos, manipuladores de janelas, sockets de rede, conexões de banco de dados, etc

Por exemplo, se você abrir um arquivo no programa e não fechá-lo após o processamento, o arquivo não estará disponível para outras operações ou ele está sendo usado por outra aplicação que não podem abrir ou modificar o arquivo. Para este fim classe FileStream fornece o método Dispose. Temos de chamar esse método após o processamento do arquivo ser concluído, caso contrário, ocorrerá  uma exceção de acesso negado ou de que o arquivo está sendo usado por outro programa.

Usando Finalize() ou Dispose()

Alguns objetos expõe os métodos Close e Dispose. Para as classes Stream ambos têm a mesma finalidade. O método Dispose() chama o método Close no seu interior.

void Dispose ()
{
         this.Close ();
}

Mas por que precisamos do método Dispose() em um Stream ?

Usando o método Dispose você poderá escrever o código abaixo e implicitamente chamar o método Dispose() e, finalmente, vai chamar o método Close.

using (FileStream arquivo = new FileStream ("caminho", FileMode.Open, FileAccess.READ))
{
// Faça algo com o arquivo
}

Mas, para algumas classes ambos os métodos se comportam um pouco diferente; Por exemplo a classe Connection.

Se o método Close() for chamado ela irá desconectar do banco de dados e liberar todos os recursos utilizados pelo objeto de conexão e o método Open vai reconectá-lo novamente com o banco de dados sem reinicializar o objeto de conexão.

Usando o método Dispose, no entanto, você libera completamente o objeto de conexão que não pode ser reaberto apenas chamando o método Open dessa forma o objeto de conexão terá que ser reiniciado.

Resumo comparativo:

Finalize Dispose
Usado para liberar recursos não gerenciados como arquivos, conexões de banco de dados, recursos COM, etc. retidos por um objeto antes que objeto seja destruído. Ele é usado para liberar recursos não gerenciados como arquivos, conexões de banco de dados, etc COM a qualquer momento.
Internamente é chamado pelo coletor de lixo e não pode ser chamado pelo código do usuário. É chamado explicitamente  pelo código do usuário, a classe que o define deve implementar a interface IDisposable.
Pertence a classe Object Pertence à interface IDisposable.
Implementar quando você tem recursos não gerenciados em seu código, e quer ter certeza de que esses recursos são liberados quando a coleta de lixo acontecer. Implementar quando você está escrevendo uma classe personalizada que será usada por outros usuários.
Há custo de desempenho associado. Não há custo de desempenho associado

Lembretes Importantes:

E estamos conversados...

João 6:37 Todo o que o Pai me dá virá a mim; e o que vem a mim de maneira nenhuma o lançarei fora.

João 6:38 Porque eu desci do céu, não para fazer a minha vontade, mas a vontade daquele que me enviou.

João 6:39 E a vontade do que me enviou é esta: Que eu não perca nenhum de todos aqueles que me deu, mas que eu o ressuscite no último dia.

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

 

             Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter
 

Referências:


José Carlos Macoratti