A prática recomendada é não forçar uma coleta de lixo.
De acordo com o MSDN:
"É possível forçar a coleta de lixo chamando Collect, mas na maioria das vezes, isso deve ser evitado porque pode criar problemas de desempenho."
No entanto, se você puder testar seu código de maneira confiável para confirmar que chamar Collect () não terá um impacto negativo, vá em frente ...
Apenas tente garantir que os objetos sejam limpos quando você não precisar mais deles. Se você tiver objetos personalizados, observe o uso de "instrução usando" e a interface IDisposable.
Este link tem alguns bons conselhos práticos com relação à liberação de memória / coleta de lixo, etc:
http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
TargetOfInvocationNullException
.Veja desta forma - é mais eficiente jogar fora o lixo da cozinha quando a lata de lixo está a 10% ou deixá-la encher antes de levá-la para fora?
Ao não deixá-lo encher, você está perdendo seu tempo indo e voltando da lixeira do lado de fora. Isso é análogo ao que acontece quando o encadeamento do GC é executado - todos os encadeamentos gerenciados são suspensos enquanto ele está em execução. E, se não me engano, o encadeamento GC pode ser compartilhado entre vários AppDomains, de forma que a coleta de lixo afeta todos eles.
Claro, você pode encontrar uma situação em que não adicionará nada à lata de lixo tão cedo - digamos, se você for tirar férias. Então, seria uma boa ideia jogar o lixo fora antes de sair.
Esta PODE ser uma vez que forçar um GC pode ajudar - se o seu programa ficar inativo, a memória em uso não é coletada como lixo porque não há alocações.
fonte
A melhor prática é não forçar uma coleta de lixo na maioria dos casos. (Todos os sistemas em que trabalhei que tinham coleta de lixo forçada, tinham problemas sublinhados que, se resolvidos, teriam removido a necessidade de forçar a coleta de lixo e acelerado muito o sistema.)
Existem alguns casos em que você sabe mais sobre o uso de memória do que o coletor de lixo. É improvável que isso seja verdade em um aplicativo multiusuário ou em um serviço que está respondendo a mais de uma solicitação por vez.
No entanto, em alguns tipos de processamento em lote você sabe mais do que o GC. Por exemplo, considere um aplicativo que.
Você pode fazer um teste (após um teste cuidadoso) de que deve forçar uma coleta de lixo completa depois de processar cada arquivo.
Outro caso é um serviço que acorda a cada poucos minutos para processar alguns itens e não mantém nenhum estado enquanto está dormindo . Então, forçar uma coleção completa antes de dormir pode valer a pena.
Eu preferiria ter uma API de coleta de lixo quando pudesse dar dicas sobre esse tipo de coisa sem ter que forçar um GC para mim.
Veja também " Dicas de desempenho de Rico Mariani "
fonte
Acho que o exemplo dado por Rico Mariani foi bom: pode ser apropriado acionar um GC se houver uma mudança significativa no estado do aplicativo. Por exemplo, em um editor de documentos, pode ser OK acionar um GC quando um documento é fechado.
fonte
Existem algumas diretrizes gerais de programação que são absolutas. Metade do tempo, quando alguém diz 'você está fazendo errado', eles estão apenas cuspindo uma certa quantidade de dogma. Em C, costumava haver medo de coisas como código ou threads de automodificação, em linguagens de GC é forçar o GC ou, alternativamente, impedir que o GC seja executado.
Como é o caso da maioria das diretrizes e boas regras (e boas práticas de design), existem raras ocasiões em que faz sentido contornar a norma estabelecida. Você tem que ter certeza de que entende o caso, de que seu caso realmente requer a revogação da prática comum e de que entende os riscos e efeitos colaterais que pode causar. Mas existem casos assim.
Os problemas de programação são amplamente variados e requerem uma abordagem flexível. Já vi casos em que faz sentido bloquear GC em linguagens com coleta de lixo e lugares onde faz sentido acioná-lo em vez de esperar que ocorra naturalmente. 95% das vezes, qualquer um desses seria um sinal de não ter abordado o problema corretamente. Mas, uma vez em cada 20, provavelmente há um caso válido a ser defendido.
fonte
Aprendi a não tentar ser mais esperto que a coleta de lixo. Com isso dito, eu apenas continuo usando
using
palavras-chave ao lidar com recursos não gerenciados, como E / S de arquivo ou conexões de banco de dados.fonte
Não tenho certeza se é uma prática recomendada, mas ao trabalhar com grandes quantidades de imagens em um loop (ou seja, criando e descartando muitos objetos Graphics / Image / Bitmap), eu regularmente deixo o GC.Collect.
Acho que li em algum lugar que o GC só funciona quando o programa está (principalmente) ocioso, e não no meio de um loop intensivo, de modo que pode parecer uma área onde o GC manual pode fazer sentido.
fonte
Um caso que encontrei recentemente que exigia chamadas manuais para
GC.Collect()
foi ao trabalhar com grandes objetos C ++ que eram agrupados em pequenos objetos C ++ gerenciados, que por sua vez eram acessados a partir do C #.O coletor de lixo nunca foi chamado porque a quantidade de memória gerenciada usada era insignificante, mas a quantidade de memória não gerenciada usada era enorme. Chamar manualmente
Dispose()
os objetos exigiria que eu acompanhasse quando os objetos não são mais necessários, enquanto a chamadaGC.Collect()
limpará todos os objetos que não são mais referidos .....fonte
GC.AddMemoryPressure (ApproximateSizeOfUnmanagedResource)
o construtor e, posteriormenteGC.RemoveMemoryPressure(addedSize)
, o finalizador. Desta forma, o coletor de lixo será executado automaticamente, levando em consideração o tamanho das estruturas não gerenciadas que podem ser coletadas. stackoverflow.com/questions/1149181/…Acho que você já listou as melhores práticas e NÃO usá-las a menos que seja REALMENTE necessário. Eu recomendo fortemente examinar seu código com mais detalhes, usando ferramentas de criação de perfil, se necessário, para responder a essas perguntas primeiro.
fonte
Suponha que seu programa não tenha vazamento de memória, objetos se acumulam e não podem ser GC-ed em Gen 0 porque: 1) Eles são referenciados por muito tempo, então entre em Gen1 e Gen2; 2) Eles são objetos grandes (> 80K), então entre no LOH (Large Object Heap). E o LOH não compacta como em Gen0, Gen1 e Gen2.
Verifique o contador de desempenho de "Memória .NET" se você pode ver que 1) o problema não é realmente um problema. Geralmente, cada 10 GC Gen0 irá acionar 1 GC Gen1 e cada 10 GC Gen1 irá desencadear 1 GC Gen2. Teoricamente, GC1 e GC2 nunca podem ser GC-ed se não houver pressão no GC0 (se o uso de memória do programa estiver realmente conectado). Isso nunca acontece comigo.
Para o problema 2), você pode verificar o contador de desempenho da "Memória .NET" para verificar se o LOH está ficando inchado. Se for realmente um problema para o seu problema, talvez você possa criar um pool de objetos grandes, como este blog sugere http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx .
fonte
Objetos grandes são alocados no LOH (heap de objeto grande), não na geração 0. Se você está dizendo que eles não são coletados como lixo com a geração 0, você está certo. Eu acredito que eles são coletados apenas quando o ciclo completo de GC (gerações 0, 1 e 2) acontece.
Dito isso, acredito que, por outro lado, o GC ajustará e coletará memória de forma mais agressiva quando você trabalhar com objetos grandes e a pressão da memória aumentar.
É difícil dizer se devemos coletar ou não e em que circunstâncias. Eu costumava fazer GC.Collect () após descartar janelas / formulários de diálogo com vários controles etc. (porque no momento em que o formulário e seus controles terminam na geração 2 devido à criação de muitas instâncias de objetos de negócios / carregamento de muitos dados - não objetos grandes obviamente), mas na verdade não notou nenhum efeito positivo ou negativo a longo prazo.
fonte
Gostaria de acrescentar que: Chamar GC.Collect () (+ WaitForPendingFinalizers ()) é uma parte da história. Como corretamente mencionado por outros, GC.COllect () é uma coleção não determinística e é deixada ao critério do próprio GC (CLR). Mesmo se você adicionar uma chamada para WaitForPendingFinalizers, ela pode não ser determinística. Pegue o código deste link do msdn e execute o código com a iteração do loop do objeto como 1 ou 2. Você descobrirá o que significa não determinístico (definir um ponto de interrupção no destruidor do objeto). Precisamente, o destruidor não é chamado quando havia apenas 1 (ou 2) objetos remanescentes por Wait .. (). [Citation reqd.]
Se o seu código estiver lidando com recursos não gerenciados (ex: identificadores de arquivo externos), você deve implementar destruidores (ou finalizadores).
Aqui está um exemplo interessante:
Nota : Se você já experimentou o exemplo acima do MSDN, o código a seguir vai limpar o ar.
Eu sugiro, primeiro analise qual poderia ser a saída e, em seguida, execute e, em seguida, leia o motivo abaixo:
{O destruidor só é chamado implicitamente quando o programa termina. } Para limpar deterministicamente o objeto, deve-se implementar IDisposable e fazer uma chamada explícita para Dispose (). Essa é a essência! :)
fonte
Mais uma coisa, acionar o GC Collect explicitamente pode NÃO melhorar o desempenho do seu programa. É bem possível piorar as coisas.
O .NET GC é bem projetado e ajustado para ser adaptável, o que significa que pode ajustar o limite GC0 / 1/2 de acordo com o "hábito" de uso de memória do programa. Assim, ele será adaptado ao seu programa após algum tempo de execução. Depois de invocar GC.Collect explicitamente, os limites serão redefinidos! E o .NET tem que gastar tempo para se adaptar ao "hábito" do seu programa novamente.
Minha sugestão é sempre confiar no .NET GC. Qualquer problema de memória surgir, verifique o contador de desempenho "Memória .NET" e diagnostique meu próprio código.
fonte
Sugestão: não implemente isso ou nada quando não tiver certeza. Reavalie quando os fatos forem conhecidos e, em seguida, execute testes de desempenho antes / depois para verificar.
fonte
IMHO, isso é semelhante a dizer "Se você pode provar que seu programa nunca terá nenhum bug no futuro, então vá em frente ..."
Com toda a seriedade, forçar o GC é útil para fins de depuração / teste. Se achar que precisa fazer isso em qualquer outro momento, ou você está enganado ou seu programa foi desenvolvido de maneira errada. De qualquer forma, a solução não é forçar o GC ...
fonte