Devo Dispose () DataSet e DataTable?

DataSet e DataTable implementam IDisposable, portanto, pelas melhores práticas convencionais, devo chamar seus methods Dispose ().

No entanto, pelo que li até agora, DataSet e DataTable não possuem resources não gerenciados, então Dispose () não faz muito.

Além disso, não posso simplesmente usar using(DataSet myDataSet...) porque DataSet tem uma coleção de DataTables.

Então, para ser seguro, eu precisaria iterar através de myDataSet.Tables, descartar cada um dos DataTables e, em seguida, descartar o DataSet.

Então, vale a pena chamar Dispose () em todos os meus DataSets e DataTables?

Termo aditivo:

Para aqueles que acham que o DataSet deve ser descartado: Em geral, o padrão para descartar é usar using ou try..finally , porque você quer garantir que Dispose () será chamado.

No entanto, isso fica feio muito rápido para uma coleção. Por exemplo, o que você faz se uma das chamadas para Dispose () lançar uma exceção? Você engole (o que é “ruim”) para que você possa continuar a eliminar o próximo elemento?

Ou, você sugere que eu chame apenas myDataSet.Dispose () e esqueça de descartar o DataTables em myDataSet.Tables?

Aqui estão algumas discussões explicando porque Dispose não é necessário para um DataSet.

Descartar ou não descartar? :

O método Dispose no DataSet existe SOMENTE devido ao efeito colateral da inheritance – em outras palavras, não faz nada de útil na finalização.

Deve Dispose ser chamado em objects DataTable e DataSet? inclui alguma explicação de um MVP:

O namespace system.data (ADONET) não contém resources não gerenciados. Portanto, não há necessidade de descartar nenhum deles, desde que você não tenha adicionado algo especial a ele.

Entendendo o método Dispose e os conjuntos de dados? tem um comentário da autoridade Scott Allen:

Na prática, raramente descartar um DataSet porque oferece pouco benefício ”

Portanto, há consenso de que atualmente não há uma boa razão para chamar Dispose em um DataSet.

Atualização (1º de dezembro de 2009):

Eu gostaria de corrigir esta resposta e admitir que a resposta original foi falha.

A análise original se aplica a objects que requerem finalização – e o ponto em que as práticas não devem ser aceitas na superfície sem um entendimento preciso e profundo ainda permanece.

No entanto, acontece que DataSets, DataViews, DataTables suprimem a finalização em seus construtores – é por isso que chamar Dispose () neles explicitamente não faz nada.

Presumivelmente, isso acontece porque eles não têm resources não gerenciados; Portanto, apesar do MarshalByValueComponent fazer concessões para resources não gerenciados, essas implementações específicas não têm a necessidade e podem, portanto, desistir da finalização.

(Que os autores do .NET cuidariam de suprimir a finalização nos mesmos tipos que normalmente ocupam a maior parte da memory falam da importância desta prática em geral para os tipos finalizáveis.)

Não obstante, esses detalhes ainda estão sub documentados desde o início do .NET Framework (quase 8 anos atrás) é bastante surpreendente (que você é essencialmente deixado para seus próprios dispositivos para peneirar material ambíguo e em conflito para juntar as peças) É frustrante às vezes, mas fornece uma compreensão mais completa da estrutura em que confiamos todos os dias).

Depois de muita leitura, aqui está o meu entendimento:

Se um object exigir a finalização, ele poderia ocupar a memory por mais tempo do que o necessário – eis o porquê: a) Qualquer tipo que define um destruidor (ou herda de um tipo que define um destruidor) é considerado finalizável; b) Na alocação (antes da execução do construtor), um ponteiro é colocado na fila de Finalização; c) Um object finalizável normalmente requer que 2 collections sejam recuperadas (em vez do padrão 1); d) Suprimir a finalização não remove um object da fila de finalização (conforme relatado por! FinalizeQueue in SOS) Esse comando é enganoso; Saber quais objects estão na fila de finalização (por si só) não é útil; Saber quais objects estão na fila de finalização e ainda precisar de finalização seria útil (existe um comando para isso?)

A supressão da finalização é desativada no header do object, indicando ao tempo de execução que ele não precisa ter seu Finalizador chamado (não precisa mover a fila FReachable); Ele permanece na fila de Finalização (e continua a ser reportado por! FinalizeQueue no SOS)

As classs DataTable, DataSet, DataView são todas baseadas em MarshalByValueComponent, um object finalizável que pode (potencialmente) manipular resources não gerenciados

  • Como DataTable, DataSet, DataView não introduzem resources não gerenciados, eles suprimem a finalização em seus construtores.
  • Embora este seja um padrão incomum, ele libera o chamador de ter que se preocupar em chamar Dispose após o uso
  • Isso e o fato de DataTables poderem ser compartilhados em diferentes DataSets provavelmente é o motivo pelo qual os DataSets não se importam em descartar DataTables filhos
  • Isso também significa que esses objects aparecerão sob o! FinalizeQueue no SOS
  • No entanto, esses objects ainda devem ser recuperáveis ​​após uma única coleta, como suas contrapartes não finalizáveis.

4 (novas referências):

Resposta Original:

Há muitas respostas equivocadas e geralmente muito ruins sobre isso – qualquer um que tenha chegado aqui deve ignorar o ruído e ler cuidadosamente as referências abaixo.

Sem dúvida, Dispose deve ser chamado em qualquer object Finalizable.

DataTables são finalizáveis.

A chamada Dispose acelera significativamente a recuperação da memory.

MarshalByValueComponent chama GC.SuppressFinalize (this) em Dispose () – pulando isso significa ter que esperar por dezenas, se não centenas, de collections Gen0 antes que a memory seja recuperada:

Com essa compreensão básica de finalização, já podemos deduzir algumas coisas muito importantes:

Primeiro, os objects que precisam de finalização vivem mais do que os objects que não precisam. Na verdade, eles podem viver muito mais tempo. Por exemplo, suponha que um object que esteja em gen2 precise ser finalizado. A finalização será agendada, mas o object ainda está no gen2, portanto, ele não será coletado novamente até que a próxima coleção do gen2 aconteça. Isso pode ser um tempo muito longo e, de fato, se as coisas estiverem indo bem, será um longo tempo, porque as collections gen2 são caras e, portanto, queremos que elas aconteçam com pouca frequência. Objetos mais antigos que precisam de finalização podem ter que esperar dezenas, senão centenas, de collections gen0 antes que seu espaço seja recuperado.

Segundo, objects que precisam de finalização causam danos colaterais. Como os pointers dos objects internos devem permanecer válidos, não apenas os objects que necessitam de finalização diretamente na memory, mas tudo o que o object se refere, direta e indiretamente, também permanecerão na memory. Se uma enorme tree de objects fosse ancorada por um único object que necessitasse de finalização, então a tree inteira permaneceria, potencialmente por muito tempo, como acabamos de discutir. Portanto, é importante usar os finalizadores com moderação e colocá-los em objects que tenham o menor número possível de pointers de objects internos. No exemplo da tree que acabei de fornecer, você pode evitar facilmente o problema movendo os resources que precisam ser finalizados para um object separado e mantendo uma referência a esse object na raiz da tree. Com essa mudança modesta, apenas o único object (esperançosamente, um belo object pequeno) permaneceria e o custo de finalização seria minimizado.

Finalmente, os objects que precisam de finalização criam trabalho para o encadeamento do finalizador. Se o seu processo de finalização for complexo, o primeiro e único thread de finalizador estará gastando muito tempo executando essas etapas, o que pode causar um backlog de trabalho e, portanto, fazer com que mais objects permaneçam aguardando a finalização. Portanto, é de vital importância que os finalizadores façam o mínimo possível de trabalho. Lembre-se também que, embora todos os pointers de object permaneçam válidos durante a finalização, pode ser que esses pointers levem a objects que já foram finalizados e possam, portanto, ser menos úteis. Geralmente, é mais seguro evitar seguir os pointers de object no código de finalização, mesmo que os pointers sejam válidos. Um caminho de código de finalização curto e seguro é o melhor.

Tirar de alguém que tenha visto 100s de MBs de DataTables não referenciados em Gen2: isso é extremamente importante e completamente perdido pelas respostas neste tópico.

Referências:

1 – http://msdn.microsoft.com/pt-br/library/ms973837.aspx

2 – http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage -collector-performance-using-finalizedispose-pattern.aspx

3 – http://codeidol.com/csharp/net-framework/Inside-the-CLR/Automatic-Memory-Management/

Você deve assumir que faz algo útil e chamar Dispose, mesmo que não faça nada na corrente. Encargos do NET Framework, não há garantias de que ele permanecerá assim em versões futuras, levando ao uso ineficiente de resources.

Mesmo que o object não tenha resources não gerenciados, o descarte pode ajudar o GC ao quebrar os charts de object. Em geral, se o object implementa IDisposable, Dispose () deve ser chamado.

Se Dispose () realmente faz alguma coisa ou não depende de determinada class. No caso de DataSet, a implementação Dispose () é herdada do MarshalByValueComponent. Ele se remove do container e chama o evento Disposed. O código fonte está abaixo (desmontado com o .NET Reflector):

 protected virtual void Dispose(bool disposing) { if (disposing) { lock (this) { if ((this.site != null) && (this.site.Container != null)) { this.site.Container.Remove(this); } if (this.events != null) { EventHandler handler = (EventHandler) this.events[EventDisposed]; if (handler != null) { handler(this, EventArgs.Empty); } } } } } 

Você cria os DataTables você mesmo? Porque iterar através dos filhos de qualquer object (como em DataSet.Tables) geralmente não é necessário, pois é o trabalho do pai para dispor todos os seus filhos.

Geralmente, a regra é: Se você criou e implementa IDisposable, Dispose it. Se você NÃO o criou, então NÃO o elimine, esse é o trabalho do object pai. Mas cada object pode ter regras especiais, verifique a Documentação.

Para o .net 3.5, explicitamente diz “Dispose it when not using anymore”, então é isso que eu faria.

Eu chamo descarte a qualquer momento que um object implemente IDisposeable. Está lá por um motivo.

Os DataSets podem ser grandes porcos de memory. Quanto mais cedo eles puderem ser marcados para limpeza, melhor.

atualizar

Faz 5 anos desde que respondi a esta pergunta. Eu ainda concordo com a minha resposta. Se houver um método de descarte, ele deverá ser chamado quando você terminar com o object. A interface IDispose foi implementada por um motivo.

Se a sua intenção ou o contexto dessa questão for realmente garbage collection, você poderá definir os conjuntos de dados e as tabelas de dados como null explicitamente ou usar a palavra-chave usando e deixá-los fora do escopo. Dispose não faz muito como Tetraneutron disse anteriormente. O GC coletará objects de dataset que não são mais referenciados e também aqueles que estão fora do escopo.

Eu realmente gostaria que as pessoas forçadas a votar realmente escrevessem um comentário antes de votar de forma negativa na resposta.

Conjuntos de dados implementam IDisposable thorough MarshalByValueComponent, que implementa IDisposable. Como os conjuntos de dados são gerenciados, não há nenhum benefício real em chamar o descarte.

Tente usar a function Clear (). Isso funciona muito bem para mim para se desfazer.

 DataTable dt = GetDataSchema(); //populate dt, do whatever... dt.Clear(); 

Antes de mais nada, eu verificaria o que Dispose faz com um DataSet. Talvez usando o refletor do redgate ajudará.

Intereting Posts