Você deve definir todos os objetos para null
( Nothing
no VB.NET) depois de terminar com eles?
Eu entendo que no .NET é essencial descartar quaisquer instâncias de objetos que implementam a IDisposable
interface para liberar alguns recursos, embora o objeto ainda possa ser algo depois de ser descartado (daí a isDisposed
propriedade nos formulários), então presumo que ele ainda possa residir na memória ou pelo menos em parte?
Sei também que quando um objeto sai do escopo, ele é marcado para coleta pronto para a próxima passagem do coletor de lixo (embora isso possa levar tempo).
Portanto, com isso em mente, será possível configurá-lo para null
acelerar o sistema que libera a memória, uma vez que não é necessário descobrir que ele não está mais no escopo e existem efeitos colaterais ruins?
Os artigos da MSDN nunca fazem isso em exemplos e, atualmente, faço isso porque não vejo o dano. No entanto, me deparei com uma mistura de opiniões, para que quaisquer comentários sejam úteis.
Respostas:
Karl está absolutamente correto, não há necessidade de definir objetos como nulos após o uso. Se um objeto for implementado
IDisposable
, certifique-se de ligarIDisposable.Dispose()
quando terminar o objeto (envolvido em umtry
..finally
ou umusing()
bloco). Mas mesmo que você não se lembre de ligarDispose()
, o método finalizador do objeto deve estar chamandoDispose()
por você.Eu pensei que este era um bom tratamento:
e isto
Não faz sentido tentar adivinhar o GC e suas estratégias de gerenciamento porque é auto-ajustável e opaco. Houve uma boa discussão sobre o funcionamento interno de Jeffrey Richter no Dot Net Rocks aqui: Jeffrey Richter no modelo de memória do Windows e no livro CLR de Richters, via CLR via C #, o capítulo 20 tem um ótimo tratamento:
fonte
Outro motivo para evitar definir objetos como nulos quando você terminar com eles é que ele pode realmente mantê-los vivos por mais tempo.
por exemplo
permitirá que o objeto referido por someType seja submetido ao GC após a chamada para "DoSomething", mas
às vezes, pode manter o objeto vivo até o final do método. O JIT geralmente otimiza a atribuição para null , portanto, os dois bits de código acabam sendo os mesmos.
fonte
GC.KeepAlive(someType);
See ericlippert.com/2013/06/10/construction-destructionNão, não faça objetos nulos. Você pode conferir http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx para obter mais informações, mas definindo as coisas nulo não fará nada, exceto sujar seu código.
fonte
Além disso:
fonte
Em geral, não é necessário anular objetos após o uso, mas, em alguns casos, acho que é uma boa prática.
Se um objeto implementa IDisposable e é armazenado em um campo, acho bom anulá-lo, apenas para evitar o uso do objeto descartado. Os erros do seguinte tipo podem ser dolorosos:
É bom anular o campo após descartá-lo e obter um NullPtrEx diretamente na linha em que o campo é usado novamente. Caso contrário, você poderá encontrar algum bug enigmático na linha (dependendo exatamente do que o DoSomething faz).
fonte
.Dispose()
. Se você o encontrar, não estará usando o IDisposable corretamente. O único uso para um objeto descartável deve estar nos limites de um bloco de uso. E após o bloco de uso, você nem tem mais acessomyField
. E dentro do bloco using, a configuração paranull
não é necessária, o bloco using descartará o objeto para você.As chances são de que seu código não seja estruturado de maneira suficientemente rígida se você sentir a necessidade de
null
variáveis.Existem várias maneiras de limitar o escopo de uma variável:
Como mencionado por Steve Tranby
Da mesma forma, você pode simplesmente usar colchetes:
Acho que usar colchetes sem nenhum "cabeçalho" para realmente limpar o código e ajudar a torná-lo mais compreensível.
fonte
O único momento em que você deve definir uma variável como nula é quando a variável não sai do escopo e você não precisa mais dos dados associados a ela. Caso contrário, não há necessidade.
fonte
Em geral, não é necessário definir como nulo. Mas suponha que você tenha uma funcionalidade Redefinir em sua classe.
Você pode fazer isso, porque não deseja chamar o descarte duas vezes, pois parte do Dispose pode não ser implementada corretamente e lança a exceção System.ObjectDisposed.
fonte
esse tipo de "não há necessidade de definir objetos como nulos após o uso" não é totalmente preciso. Há momentos em que você precisa NULL a variável após descartá-la.
Sim, você sempre deve ligar
.Dispose()
ou usar.Close()
qualquer coisa que tenha quando terminar. Seja identificadores de arquivo, conexões de banco de dados ou objetos descartáveis.Separado disso, está o padrão muito prático do LazyLoad.
Digamos que eu tenha e instanciado
ObjA
declass A
.Class A
tem uma propriedade pública chamadaPropB
declass B
.Internamente,
PropB
usa a variável privada de_B
e o padrão é null. QuandoPropB.Get()
é usado, ele verifica para ver se_PropB
é nulo e se for, abre os recursos necessários para instanciar umB
em_PropB
. Em seguida, retorna_PropB
.Para minha experiência, este é um truque realmente útil.
Onde a necessidade de nulo aparece é se você redefinir ou alterar A de alguma forma que o conteúdo
_PropB
fosse filho dos valores anterioresA
, será necessário Dispose AND null out_PropB
para que LazyLoad possa redefinir para buscar o valor correto SE o código requer isso.Se você fizer isso
_PropB.Dispose()
e logo depois esperar que a verificação nula do LazyLoad seja bem-sucedida, ela não será nula e você verá dados obsoletos. Na verdade, você deve anulá-lo depoisDispose()
apenas para ter certeza.Eu certamente gostaria que fosse de outro modo, mas agora tenho código que exibe esse comportamento depois de uma função
Dispose()
a_PropB
e fora da função de chamada que fez o Dispose (e, portanto, quase fora do escopo), o objeto privado ainda não é nulo, e os dados antigos ainda estão lá.Eventualmente, a propriedade descartada será anulada, mas isso não foi determinista da minha perspectiva.
O principal motivo, como o dbkk faz alusão, é que o contêiner pai (
ObjA
comPropB
) mantém a instância_PropB
no escopo, apesar doDispose()
.fonte
Existem alguns casos em que faz sentido anular referências. Por exemplo, ao escrever uma coleção - como uma fila de prioridade - e pelo seu contrato, você não deve manter esses objetos ativos para o cliente depois que o cliente os remove da fila.
Mas esse tipo de coisa só importa em coleções de vida longa. Se a fila não sobreviver ao final da função em que foi criada, isso importa muito menos.
No geral, você realmente não deveria se preocupar. Deixe o compilador e o GC fazerem o trabalho deles para que você possa fazer o seu.
fonte
Dê uma olhada neste artigo também: http://www.codeproject.com/KB/cs/idisposable.aspx
Na maioria das vezes, definir um objeto como nulo não tem efeito. O único momento em que você deve fazer isso é se estiver trabalhando com um "objeto grande", que é maior que 84K de tamanho (como bitmaps).
fonte
Stephen Cleary explica muito bem neste post: Devo definir variáveis como nulo para ajudar na coleta de lixo?
Diz:
O importante que devemos considerar são os campos estáticos .
Conclusão:
fonte
Acredito que, pelo design dos implementadores de GC, você não pode acelerar o GC com a anulação. Tenho certeza de que eles preferem que você não se preocupe com como / quando o GC é executado - trate-o como este Onipresente Sendo protegendo e cuidando de você ... (inclina a cabeça, levanta o punho para o céu) .. .
Pessoalmente, geralmente defino explicitamente variáveis como nulas quando termino com elas como uma forma de auto-documentação. Não declaro, uso e defino como nulo mais tarde - anulo imediatamente depois que eles não são mais necessários. Estou dizendo, explicitamente: "Eu terminei oficialmente com você ... se foi ..."
A anulação é necessária em um idioma do GC? Não. É útil para o GC? Talvez sim, talvez não, não sei ao certo, por design, eu realmente não posso controlá-lo e, independentemente da resposta de hoje com esta versão ou aquela, futuras implementações de GC podem mudar a resposta além do meu controle. Além disso, se / quando a anulação for otimizada, será pouco mais que um comentário sofisticado, se você desejar.
Eu acho que se isso esclarece minha intenção para o próximo pobre idiota que segue meus passos, e se "pode" potencialmente ajudar a GC algumas vezes, então vale a pena para mim. Principalmente, isso me faz sentir arrumado e claro, e Mongo gosta de me sentir arrumado e claro. :)
Eu vejo assim: Linguagens de programação existem para permitir que outras pessoas tenham uma idéia da intenção e um compilador faça uma solicitação de trabalho sobre o que fazer - o compilador converte essa solicitação em um idioma diferente (às vezes várias) para uma CPU - a (s) CPU (s) podem dizer o que você usou, as configurações de sua guia, comentários, ênfases estilísticas, nomes de variáveis, etc. Muitas coisas escritas no código não se convertem no que é consumido pela CPU na sequência especificada. Nosso C, C ++, C #, Lisp, Babel, assembler ou o que quer que seja teoria e não realidade, escrito como uma declaração de trabalho. O que você vê não é o que você recebe, sim, mesmo na linguagem assembler.
Entendo que a mentalidade de "coisas desnecessárias" (como linhas em branco) "nada mais é do que barulho e confusão de código". Essa fui eu no início da minha carreira; Eu entendo isso totalmente. Neste momento, eu me inclino para o que torna o código mais claro. Não é como se eu estivesse adicionando até 50 linhas de "ruído" aos meus programas - são algumas linhas aqui ou ali.
Há exceções para qualquer regra. Em cenários com memória volátil, memória estática, condições de corrida, singletons, uso de dados "obsoletos" e todo esse tipo de apodrecimento, isso é diferente: você PRECISA gerenciar sua própria memória, bloqueando e anulando conforme apropriado, porque a memória não faz parte da memória. o universo da GC - espero que todos entendam isso. O resto do tempo com os idiomas do GC é uma questão de estilo, e não de necessidade ou um aumento garantido de desempenho.
No final do dia, entenda o que é elegível para o GC e o que não é; bloquear, descartar e anular adequadamente; cera, cera; inspire, expire; e por tudo o mais eu digo: se é bom, faça. Sua milhagem pode variar ... como deveria ...
fonte
Eu acho que definir algo de volta para null é confuso. Imagine um cenário em que o item que está sendo definido agora seja exposto, digamos, através da propriedade Agora, de alguma forma, algum pedaço de código acidentalmente usa essa propriedade depois que o item é descartado, você receberá uma exceção de referência nula que requer alguma investigação para descobrir exatamente o que está acontecendo.
Acredito que os descartáveis de estrutura permitirão lançar ObjectDisposedException que é mais significativo. Não configurá-los de volta para nulo seria melhor do que por esse motivo.
fonte
Algum objeto supõe o
.dispose()
método que força o recurso a ser removido da memória.fonte