Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Uso de Destrutores

Reparei que ainda não se abordou o tópico de destrutores, mas apenas de construtores (aliás, não sei se mais adiante há esse tópico nos cursos de C#). No caso do uso de strings com Remove, se é usada internamente a troca de uma string por uma nova e um apontamento da variável da antiga para o objeto novo, isso é feito internamente no C#? Se não for assim, um método iterativo, como um While, pode encher a memória de objetos largados pra trás. Como garantir que o objeto String antigo foi destruído? Não deveríamos ter um destrutor sobrescrevendo o original? Não consigo ver na documentação de String a implementação de um destrutor.

4 respostas

Oi José tudo bem?

Não há esse tópico nos cursos de C# da Alura. O C# (assim como o Java) tem um dispositivo interno chamado garbage collector que automaticamente vai limpando da mémoria RAM as variáveis e objetos não mais usados. Então ninguém se preocupa em destruir objetos porque isso é feito de forma automática.

Espero ter ajudado!

Olá, André, tudo bem?

Sim ,garbage colector é algo que eles implementaram pegando a ideia do Java, eu sei. Porém nenhum garbage colector é 100% confiável, pois existem situações que podem burlar a ação dele. Não há como prever num ambiente de produção que uma aplicação complexa, com múltiplas conexões de múltiplos usuários, não vai ter um leak e consumir os recursos da máquina. Daí a necessidade de se tomar o cuidado de verificar que seus recursos estão sendo liberados.

Para tanto pode-se acrescentar em suas classes a interface IDisposable e usar um bloco using para garantir que ao fim do processo, o método Dispose() seja chamado, e colocar no destrutor código especial para liberar recursos, sejam de conexão, arquivo aberto, acesso a banco de dados etc. A interface até é mencionada num dos cursos, mas não se fala de aproveitar os destrutores.

Os destrutores têm sintaxe semelhante aos dos construtores, mas com um til na frente. Já testei no Visual Studio, e funciona. De qualquer forma, sugiro que dêem uma olhada nessa funcionalidade para incluir no curso, em tópicos de boas práticas.

Obrigado pelo retorno.

solução!

Olá, José. Tudo bom com você?

No caso do uso de strings com Remove, se é usada internamente a troca de uma string por uma nova e um apontamento da variável da antiga para o objeto novo, isso é feito internamente no C#?

  • Não é feito internamente. No código abaixo:
    string teste = "abc";
    teste.Remove('a');
    Console.WriteLine(teste); // abc
    A saída será "abc". O que acontece é que o Remove retorna outra string e você que deverá capturar:
    string teste = "abc";
    teste = teste.Remove('a');
    Console.WriteLine(teste); // bc

Se não for assim, um método iterativo, como um While, pode encher a memória de objetos largados pra trás. Como garantir que o objeto String antigo foi destruído?

  • Não temos essa garantia! De qualquer modo, o garbage collector do C# é bastante esperto e neste tipo de situação ele vai limpar a memória.

Não deveríamos ter um destrutor sobrescrevendo o original?

  • Não.

Nesta série de curso não abordamos o assunto de destrutores/finalizadores. A boa prática é não os utilizar.

No C# não é possível ativamente remover um objeto da memória, quem sempre faz isto é o GC e não sabemos quando que isto acontece.

Já que é assim, qual seria o sentido da existência dos destrutores/finalizadores no C#? Em alguns cenários bem específicos, você vai querer executar algum código quando o GC remover um objeto da memória do computador. Esta abordagem é usada em códigos críticos, porque apesar de existir o padrão de disposables, ainda é possível que a pessoa não execute o código de um IDisposable em um bloco using ou que chame o método Dispose.

Mas... Destrutores são realmente estranhos:

  • Não podemos prever quando são executados;
  • Às vezes o objeto sai da memória e o GC não executa o finalizer;
  • Não fazemos ideia do estado do objeto quando o finalizer é executado. Talvez as propriedades do objeto já tenham sido removidas da memória e você não poderá acessar;
  • Existe um limite de tempo para a execução do finalizer, que é diferente para algumas versões do .NET;
  • Não sabemos em qual thread o finalizer está sendo executado;
  • Finalizers podem "ressuscitar" um objeto e fazer o GC mudar de ideia sobre o remover da memória!

É um assunto bastante complexo que fica fora do escopo dessa série de cursos. Para entender a fundo todos os por quês da complexidade dos finalizadores o material dessa série também não será o suficiente, mas, se depois você quiser se aprofundar em como o .NET funciona por dentro e essa questão do garbage collector e finalizadores, eu conheço e recomendo os dois livros a seguir (infelizmente somente em inglês):

Obrigado pela explicação e pelas referências de bibliografia.