Definindo Objetos para Null / nada após o uso em .NET

votos
173

Se você definir todos os objetos para null( Nothingem VB.NET) depois de ter terminado com eles?

Eu entendo que em .NET é essencial dispor de todas as instâncias de objetos que implementam a IDisposableinterface para liberar alguns recursos, embora o objeto ainda pode ser algo depois de ser eliminados (daí a isDisposedpropriedade em formulários), por isso suponho que ainda pode residir na memória ou pelo menos em parte?

Sei também que quando um objeto sai do escopo é então marcado para coleta de pronto para o próximo passo do coletor de lixo (embora isso pode levar algum tempo).

Então, com isso em mente irá defini-la para nullacelerar o sistema de liberação de memória, uma vez que não tem que trabalhar para fora que ele não está mais em escopo e são eles quaisquer efeitos colaterais ruins?

artigos do MSDN nunca fazem isso em exemplos e atualmente eu faço isso como eu não pode ver o mal. No entanto eu vim através de uma mistura de opiniões assim quaisquer comentários são úteis.

Publicado 05/08/2008 em 21:14
fonte usuário
Em outras línguas...                            


13 respostas

votos
66

Karl é absolutamente correto, não há necessidade de definir objetos para nula após o uso. Se um objeto implementa IDisposable, apenas certifique-se chamar IDisposable.Dispose()quando você está feito com esse objeto (envolto em um try.. finally, ou um using()bloco). Mas mesmo se você não se lembrar de chamar Dispose()o método finaliser sobre o objeto deve ser chamado Dispose()para você.

Eu pensei que este era um bom tratamento:

Cavando IDisposable

e isto

compreender IDisposable

Não há qualquer sentido em tentar adivinhar a suas estratégias de gestão de GC e porque é auto-ajuste e opaco. Houve uma boa discussão sobre o funcionamento interno com Jeffrey Richter em rochas Dot Net aqui: Jeffrey Richter no modelo de memória do Windows e Richters livro CLR via C # capítulo 20 tem um ótimo tratamento:

Respondeu 05/08/2008 em 21:56
fonte usuário

votos
33

Outra razão para evitar a criação de objetos como nulo quando você está feito com eles é que ele pode realmente mantê-los vivos por mais tempo.

por exemplo

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is now eligible for garbage collection         

    // ... rest of method not using 'someType' ...
}

permitirá que o objeto referido por SomeType a ser GC'd após a chamada para "DoSomething", mas

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is NOT eligible for garbage collection yet
    // because that variable is used at the end of the method         

    // ... rest of method not using 'someType' ...
    someType = null;
}

pode, por vezes, manter o objeto vivo até o fim do método. O JIT geralmente será optimizada distância a atribuição para nulo , de modo que ambos os bits de código acabar por ser o mesmo.

Respondeu 15/08/2008 em 15:43
fonte usuário

votos
15

Sem fazer objetos não nulos. Você pode conferir http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx para mais informações, mas colocar as coisas como nulo não vai fazer nada, a não ser sujo seu código.

Respondeu 05/08/2008 em 21:23
fonte usuário

votos
7

Em geral, não há nenhuma necessidade para null objetos após o uso, mas em alguns casos eu acho que é uma boa prática.

Se um objeto implementa IDisposable e é armazenado em um campo, eu acho que é bom para null-lo, apenas para evitar o uso do objeto descartado. Os erros do seguinte tipo pode ser doloroso:

this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();

É bom para anular o campo após a eliminação dele, e obter um direito NullPtrEx na linha onde o campo é usado novamente. Caso contrário, você pode executar em algum bug enigmática para baixo da linha (dependendo exatamente o que DoSomething faz).

Respondeu 09/08/2008 em 12:16
fonte usuário

votos
7

Além disso:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
Respondeu 05/08/2008 em 21:37
fonte usuário

votos
6

As chances são de que seu código não está estruturado com força suficiente, se você sentir a necessidade de nullvariáveis.

Há uma série de maneiras para limitar o escopo de uma variável:

Como mencionado por Steve Tranby

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of

Da mesma forma, você pode simplesmente usar chaves:

{
    // Declare the variable and use it
    SomeObject object = new SomeObject()
}
// The variable is no longer available

Eu acho que o uso de chaves sem qualquer "título" para realmente limpar o código e ajudar a torná-lo mais compreensível.

Respondeu 09/08/2008 em 13:13
fonte usuário

votos
5

Em geral não há necessidade de definir como nulo. Mas suponha que você tem uma funcionalidade de redefinição em sua classe.

Então você pode fazer, porque você não quer chamar dispor duas vezes, uma vez que alguns dos Descarte não pode ser implementado corretamente e jogar exceção System.ObjectDisposed.

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }
Respondeu 17/04/2012 em 09:55
fonte usuário

votos
4

A única vez que você deve definir uma variável como nulo é quando a variável não ir fora do escopo e você não precisa os dados associados a ela. Caso contrário, não há necessidade.

Respondeu 05/08/2008 em 21:32
fonte usuário

votos
3

este tipo de "não há necessidade de definir objetos como null após o uso" não é inteiramente correta. Há momentos em que você precisa para NULL a variável após a eliminação lo.

Sim, você deve sempre chamar .Dispose()ou .Close()em qualquer coisa que tem que quando você está feito. Seja arquivo alças, conexões de banco de dados ou objetos descartáveis.

Separado do que é o padrão muito prático de LazyLoad.

Digamos que eu tenha e instanciado ObjAde class A. Class Atem uma propriedade pública chamada PropBde class B.

Internamente, PropBusa a variável privada de _Be padrões para null. Quando PropB.Get()é usado, ele verifica para ver se _PropBé nulo e se for, abre os recursos necessários para instanciar um Bem _PropB. Ele então retorna _PropB.

Para minha experiência, este é um truque muito útil.

Onde a necessidade de nulo vem é se você redefinir ou alterar um, de alguma forma que o conteúdo _PropBfosse a criança dos valores anteriores A, você vai precisar descartar e nulos fora _PropBtão LazyLoad pode redefinir para buscar o valor correto se o código exige.

Se você só fazer _PropB.Dispose()e pouco tempo depois esperar que o cheque nulo para LazyLoad para ter sucesso, não será nulo, e você vai estar a olhar para dados obsoletos. Na verdade, você deve nulo lo depois Dispose()só para ter certeza.

Eu com certeza gostaria que fosse de outra forma, mas eu tenho código agora exibindo esse comportamento depois de um Dispose()em um _PropBe fora da função de chamada que fez o Dispose (e, portanto, quase fora de alcance), o prop privado ainda não é nulo, e os dados obsoletos ainda está lá.

Eventualmente, a propriedade disposta vai nulo, mas que tem sido não-determinista da minha perspectiva.

A razão núcleo, como dbkk alude é que o recipiente principal ( ObjAcom PropB) é manter o exemplo de _PropBno seu âmbito, apesar da Dispose().

Respondeu 11/04/2012 em 02:12
fonte usuário

votos
1

Dê uma olhada neste artigo, bem como: http://www.codeproject.com/KB/cs/idisposable.aspx

Para a maior parte, a criação de um objeto para nulo não tem efeito. A única vez que você deve ter certeza de fazer isso é se você estiver trabalhando com um "objeto grande", que é uma maior do que 84k em tamanho (como bitmaps).

Respondeu 17/08/2008 em 05:46
fonte usuário

votos
1

Há alguns casos onde faz sentido para null referências. Por exemplo, quando você está escrevendo uma coleção - como uma fila de prioridade - e pelo seu contrato, você não deve ser manter esses objetos vivos para o cliente após o cliente ter removido-los da fila.

Mas esse tipo de coisa só importa no longo viveram coleções. Se a fila não vai sobreviver ao fim da função em que foi criado, em seguida, ele importa muito menos.

Em um todo, você realmente não deve se preocupar. Deixe o compilador e GC fazer o seu trabalho para que você possa fazer o seu.

Respondeu 05/08/2008 em 21:46
fonte usuário

votos
0

Acredito que por predefinição dos implementadores GC, você não pode acelerar o GC com anulação. Tenho certeza de que eles preferem não se preocupe-se com a forma como / quando GC é executado - tratá-lo como este onipresente Ser protegendo e vigiando e para fora para você ... (arcos de cabeça para baixo, levanta o punho para o céu) .. .

Pessoalmente, eu muitas vezes explicitamente definir variáveis ​​como nulo quando eu terminar com eles como uma forma de auto documentação. Eu não declarar, usar, em seguida, definir como nulo depois - I nulo imediatamente após eles não são mais necessários. Estou dizendo que, explicitamente, "Eu sou feito oficialmente com você ... se foi ..."

É anular necessário em uma linguagem GC'd? Não. É útil para o GC? Talvez sim, talvez não, não sei ao certo, pelo projeto Eu realmente não posso controlar isso, e independentemente da resposta de hoje com esta versão ou que, futuras implementações de GC poderia alterar a resposta além do meu controle. Além disso, se / quando anulamento é otimizado para fora, é pouco mais do que uma fantasia comentário se você quiser.

Acho que se torna mais clara a minha intenção para o próximo tolo pobre que segue os meus passos, e se ele "poderia" potencialmente ajudar GC às vezes, então vale a pena para mim. Principalmente isso me faz sentir limpo e claro, e Mongo gosta de se sentir limpo e claro. :)

Eu olhar para ele assim: existem linguagens de programação para permitir que as pessoas dão outras pessoas uma idéia de intenções e um compilador de um pedido de emprego do que fazer - o compilador converte esse pedido em um idioma diferente (por vezes várias) para uma CPU - a CPU (s) poderia dar uma buzina que língua você usou, suas configurações da guia, comentários, ênfases estilísticas, nomes de variáveis, etc. - uma CPU é tudo sobre o fluxo de bits que lhe diz o que registra e opcodes e locais de memória para mexer. Muitas coisas escritas em código não converter em que é consumido pela CPU na seqüência nós especificado. Nossa C, C ++, C #, Lisp, Babel, assembler ou o que é a teoria, em vez de realidade, escrito como uma declaração de trabalho. O que você vê não é o que você começa, sim, mesmo em linguagem assembler.

Eu entendo a mentalidade de "coisas desnecessárias" (como linhas em branco) "não são nada, mas o ruído e atravancam código." Isso foi me no início da minha carreira; Eu entendo totalmente isso. Nesta conjuntura eu inclinar-se para o que torna o código mais claro. Não é como se eu estou adicionando até 50 linhas de "ruído" para meus programas - é algumas linhas aqui ou ali.

Há exceções a qualquer regra. Em cenários com memória volátil, memória estática, condições de corrida, singletons, o uso de dados "obsoletos" e todo esse tipo de podridão, que é diferente: você precisa gerenciar sua própria memória, bloqueio e anulando como propósito porque a memória não é parte do Universo GC'd - espero que todos entendam isso. O resto do tempo com línguas GC'd é uma questão de estilo em vez de necessidade ou um aumento de desempenho garantido.

No final do dia, certifique-se de compreender o que é elegível para o GC eo que não é; bloquear, dispor, e anular de forma adequada; cera sobre, cera fora; respirar, expire; e para tudo o resto eu digo: Se ele se sente bem, fazê-lo. Sua milhagem pode variar ... como deveria ...

Respondeu 10/05/2016 em 13:07
fonte usuário

votos
-1

Algum objeto suponha que o .dispose()método que força o recurso a ser removido da memória.

Respondeu 05/08/2008 em 21:21
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more