Anatomia de um "vazamento de memória"

votos
159

Na perspectiva NET:

  • O que é um vazamento de memória ?
  • Como você pode determinar se suas aplicação fugas? Quais são os efeitos?
  • Como você pode evitar um vazamento de memória?
  • Se seu aplicativo tem vazamento de memória, ele vai embora quando o processo sai ou é morto? Ou vazamentos de memória em sua aplicação afetam outros processos no sistema, mesmo após a conclusão do processo?
  • E o que dizer de código não gerenciado acessada através de interoperabilidade e / ou P / Invoke?
Publicado 01/08/2008 em 16:12
fonte usuário
Em outras línguas...                            


15 respostas

votos
106

A melhor explicação que eu vi é no capítulo 7 do livre Fundamentos de Programação e-book .

Basicamente, em .NET um vazamento de memória ocorre quando os objetos referenciados estão enraizados e, portanto, não pode ser lixo coletado. Isso ocorre acidentalmente quando você segurar referências além do alcance visado.

Você vai saber que você tem vazamentos quando você começar a receber OutOfMemoryExceptions ou seu uso de memória sobe além do que você esperaria ( PerfMon tem contadores de memória agradáveis).

Compreender NET modelo de memória 's é a melhor maneira de evitá-lo. Especificamente, entender como o coletor de lixo funciona e como referências trabalhar - mais uma vez, eu encaminhá-lo para o capítulo 7 do e-book. Além disso, estar atento a armadilhas comuns, provavelmente os eventos que são mais comuns. Se o objeto A é registrado para um evento no objeto B , então objeto Um vai ficar por até objeto B desaparece porque B contém uma referência para um . A solução é cancelar o registro seus eventos quando você está feito.

Claro, um bom perfil de memória vai deixar você ver seus gráficos de objetos e explorar a nidificação / referenciação de seus objetos para ver onde as referências estão vindo e que objeto raiz é responsável ( formigas-gate vermelho perfil , JetBrains dotMemory, memprofiler são realmente bons escolhas, ou você pode usar o texto somente WinDbg e SOS , mas eu recomendo fortemente um produto comercial / visuais a menos que você é um verdadeiro guru).

Acredito código não gerenciado está sujeita a seus vazamentos de memória típicos, exceto que as referências partilhadas são geridos pelo coletor de lixo. Eu posso estar errado sobre este último ponto.

Respondeu 01/08/2008 em 16:28
fonte usuário

votos
32

Estritamente falando, um vazamento de memória está consumindo memória que "não é mais usado" pelo programa.

"Deixou de ser utilizado" tem mais de um significado, isso poderia significar "não mais referência a ele", isto é, totalmente irrecuperável, ou poderia significar, referenciada, recuperável, não utilizado, mas o programa mantém as referências de qualquer maneira. Só mais tarde se aplica a NET para objetos perfeitamente gerenciados . No entanto, nem todas as classes são perfeitos e em algum momento uma implementação não gerenciado subjacente pode vazar recursos permanentemente para esse processo.

Em todos os casos, a aplicação consome mais memória do que o estritamente necessário. Os efeitos lados, dependendo do ammount vazou, poderia ir de nenhum, a desaceleração causada pela coleta excessiva, a uma série de exceções de memória e, finalmente, um erro fatal seguido por encerramento do processo forçada.

Você sabe que um aplicativo tem um problema de memória quando o monitoramento mostra que mais e mais memória é alocada para o seu processo depois de cada ciclo de coleta de lixo . Nesse caso, você está ou manter muito na memória, ou alguma implementação não gerenciado subjacente está vazando.

Para a maioria dos vazamentos, os recursos são recuperados quando o processo é encerrado, no entanto, alguns recursos não são sempre recuperados em alguns casos precisos, GDI alças cursor são notórias para isso. Claro, se você tem um mecanismo de comunicação entre processos, memória alocada em outro processo não seria libertado até que o processo libera-lo ou termina.

Respondeu 01/08/2008 em 18:52
fonte usuário

votos
28

Eu acho que o "o que é um vazamento de memória" e "Quais são os efeitos" perguntas foram bem respondidas já, mas eu queria acrescentar mais algumas coisas sobre as outras questões ...

Como entender se suas aplicação fugas

Uma maneira interessante é abrir perfmon e adicionar traços para # bytes em todas as pilhas e # Gen 2 arrecadações , em cada caso, procurando apenas no seu processo. Se exercer uma determinada característica faz com que o total de bytes a aumentar, e que a memória permanece alocada após a próxima coleção Gen 2, que você pode dizer que o recurso de vazamentos de memória.

Como prevenir

Outras boas opiniões foram dadas. Gostaria apenas de acrescentar que talvez o mais comumente negligenciado causa de vazamentos de memória .NET é adicionar manipuladores de eventos para objetos sem removê-los. Um manipulador de eventos anexado a um objeto é uma forma de referência a esse objeto, de modo impedirá coleção, mesmo depois de todas as outras referências passaram. Lembre-se sempre de separar os manipuladores de eventos (usando a -=sintaxe em C #).

Será que o vazamento desaparecem quando o processo é encerrado, e que sobre interoperabilidade COM?

Quando seus sai do processo, toda a memória mapeada em seu espaço de endereço é recuperado pelo sistema operacional, incluindo quaisquer objetos COM servido das DLLs. Comparativamente raramente, objetos COM podem ser servidos a partir de processos separados. Neste caso, quando o processo sai, você ainda pode ser responsável pela memória alocada em quaisquer processos de servidor COM que você usou.

Respondeu 15/08/2008 em 17:11
fonte usuário

votos
18

Se você precisa para diagnosticar um vazamento de memória no .NET, verifique estes links:

http://msdn.microsoft.com/en-us/magazine/cc163833.aspx

http://msdn.microsoft.com/en-us/magazine/cc164138.aspx

Esses artigos descrevem como criar um despejo de memória do seu processo e como analisá-las de modo que você pode primeiro determinar se o vazamento é não gerenciado ou geridos, e se ele é gerido, como descobrir onde ele está vindo.

A Microsoft também tem uma ferramenta nova para ajudar com a geração de despejos de memória, para substituir ADPlus, chamado DebugDiag.

http://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en

Respondeu 15/08/2008 em 00:16
fonte usuário

votos
18

Eu definiria vazamentos de memória como um objeto não liberando toda a memória alocada depois que ele foi concluída. Eu descobri isso pode acontecer em sua aplicação se você estiver usando o Windows API e COM (ie código não gerenciado que tem um bug nele ou não está a ser gerido corretamente), no âmbito e em componentes de terceiros. Eu também não foi achado tiding-se depois de usar certos objetos como canetas podem causar o problema.

Eu, pessoalmente, sofreu Out of memória exceções que podem ser causados, mas não são exclusivos para vazamentos de memória em aplicativos dot net. (OOM também pode vir de pinagem ver Pinning artical ). Se você não está recebendo erros OOM ou precisa confirmar se é um vazamento de memória fazendo com que, em seguida, o único caminho é o seu perfil de aplicação.

Também gostaria de tentar garantir o seguinte:

a) Tudo que implementa IDisposable sejam eliminados ou usando um bloco finally ou a instrução usando estes incluem escovas, canetas etc. (algumas pessoas argumentam para definir tudo para nada além)

b) Qualquer coisa que tenha um método perto está fechado novamente usando finally ou a instrução using (apesar de eu ter encontrado usando não dependendo sempre perto se você declarou o objeto fora a instrução usando)

c) Se você estiver usando código não gerenciado / API do Windows é que estes são tratados corretamente depois. (Alguns têm limpar métodos para liberar os recursos)

Espero que isto ajude.

Respondeu 01/08/2008 em 18:57
fonte usuário

votos
15

Usando CLR Profiler da Microsoft http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en é uma ótima maneira de determinar quais objetos estão segurando memória, leads de fluxo que execução para a criação desses objetos, e também monitorar quais objetos ao vivo, onde na pilha (fragmentação, LOH, etc.).

Respondeu 16/08/2008 em 20:54
fonte usuário

votos
14

A melhor explicação de como o coletor de lixo funciona é em Jeff Richter CLR via C # livro, (cap. 20). Lendo isso dá uma grande ligação à terra para compreender como os objetos persistem.

Uma das causas mais comuns de enraizamento objetos acidentalmente é de ligar eventos outisde uma classe. Se você ligar um evento externo

por exemplo

SomeExternalClass.Changed += new EventHandler(HandleIt);

e se esqueça de desligar a ele quando descartar, então SomeExternalClass tem um ref para sua classe.

Como mencionado acima, o profiler de memória SciTech é excelente no mostrando-lhe raízes de objetos você suspeitar que estão vazando.

Mas há também uma maneira muito rápida de verificar um tipo particular é só usar WnDBG (você ainda pode usar isso na janela imediata do VS.NET enquanto em anexo):

.loadby sos mscorwks
!dumpheap -stat -type <TypeName>

Agora fazer algo que você acha que vai dispor os objetos desse tipo (por exemplo, fechar uma janela). É útil aqui para ter um lugar botão de depuração que será executado System.GC.Collect()um par de vezes.

Em seguida, execute !dumpheap -stat -type <TypeName>novamente. Se o número não ir para baixo, ou não ir para baixo tanto quanto você espera, então você tem uma base para uma investigação mais aprofundada. (I com esta ponta a partir de um seminário dado por Ingo Rammer ).

Respondeu 27/08/2008 em 15:12
fonte usuário

votos
14

Eu acho que em um ambiente gerenciado, um vazamento seria você manter uma referência desnecessária a um grande pedaço de memória ao redor.

Respondeu 01/08/2008 em 16:19
fonte usuário

votos
10

Por que as pessoas pensam que um vazamento de memória no .NET não é o mesmo que qualquer outro vazamento?

Um vazamento de memória é quando você anexar a um recurso e não deixá-lo ir. Você pode fazer isso tanto em gerenciado e na codificação não gerenciado.

Em relação à NET, e outras ferramentas de programação, houve idéias sobre a coleta de lixo, e outras formas de minimizar situações que tornarão a sua fuga de aplicação. Mas o melhor método de prevenção de vazamentos de memória é que você precisa entender o seu modelo de memória subjacente, e como as coisas funciona, na plataforma que você está usando.

Acreditando que GC e outras magia vai limpar sua bagunça é o caminho curto para vazamentos de memória, e será difícil encontrar mais tarde.

Ao codificar não gerenciado, você normalmente não se esqueça de limpar, você sabe que os recursos que você toma a preensão de, será de sua responsabilidade para limpar, não o zelador do.

Em .NET, por outro lado, muitas pessoas pensam que o GC irá limpar tudo. Bem, ele faz algumas para você, mas você precisa ter certeza de que é assim. .NET que envolva muitas coisas, para que nem sempre sabem se você está lidando com um recurso gerenciado ou não, e você precisa ter certeza de que o que você está lidando. fontes manipulação, recursos GDI, diretório ativo, bancos de dados, etc é tipicamente coisas que você precisa olhar para fora.

Em termos gerenciados vou colocar meu pescoço na linha para dizer que não vai embora assim que o processo é morto / removido.

Eu vejo muitas pessoas têm este embora, e eu realmente espero que isso vai acabar. Você não pode pedir ao utilizador para terminar seu aplicativo para limpar sua bagunça! Dê uma olhada em um navegador, que pode ser IE, FF etc, então aberta, por exemplo, Google Reader, deixe ficar por alguns dias e ver o que acontece.

Se você, em seguida, abrir outra aba no navegador, navegar para algum site, em seguida, fechar a aba que sediou a outra página que fez o vazamento navegador, você acha que o navegador irá liberar a memória? Não é assim com o IE. No meu computador IE facilmente comer 1 GiB de memória em um curto espaço de tempo (cerca de 3-4 dias) se eu usar o Google Reader. Alguns newspages são ainda piores.

Respondeu 01/09/2008 em 13:19
fonte usuário

votos
10

Eu acho que em um ambiente gerenciado, um vazamento seria você manter uma referência desnecessária a um grande pedaço de memória ao redor.

Absolutamente. Além disso, não usando o método .Dispose () em objetos descartáveis ​​quando apropriado pode causar vazamentos de mem. A maneira mais fácil de fazer isso é com um bloco usando porque ele automaticamente executa .Dispose () no final:

StreamReader sr;
using(sr = new StreamReader("somefile.txt"))
{
    //do some stuff
}

E se você criar uma classe que está usando objetos não gerenciados, se você não está implementando IDisposable corretamente, você poderia estar causando vazamentos de memória para os usuários da sua classe.

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

votos
9

Todos os vazamentos de memória são resolvidas por encerramento do programa.

Vazamento de memória suficiente e o sistema operacional pode decidir resolver o problema em seu nome.

Respondeu 04/08/2008 em 15:09
fonte usuário

votos
9

Eu vou concordar com Bernard como no .net que um vazamento de mem seria.

Você poderia perfil de seu aplicativo para ver seu uso de memória, e determinar que, se a sua gestão de uma grande quantidade de memória quando não deveria ser você poderia dizer que tem um vazamento.

Em termos gerenciados vou colocar meu pescoço na linha para dizer que não vai embora assim que o processo é morto / removido.

código não gerenciado é a sua própria besta e se um vazamento existe dentro dele, ele vai seguir um mem padrão. vazar definição.

Respondeu 01/08/2008 em 16:23
fonte usuário

votos
7

Também tenha em mente que o .NET tem dois montes, sendo um heap de objeto grande. Acredito objetos de cerca de 85k ou maior são colocados nessa pilha. Este montão tem regras diferentes da vida do que a pilha regular.

Se você estiver criando estruturas de memória grandes (Dicionário das ou a lista de) seria prudente ir pesquisar quais são as regras exatas são.

Na medida em que recuperar a memória na finalização do processo, a menos que seu rodando Win98 ou equivalentes, tudo é liberado de volta para o sistema operacional em caso de cessação. As únicas exceções são as coisas que são abertos cross-processo e outro processo ainda tem o recurso aberto.

COM objetos podem ser tho complicado. Se você sempre usar o IDisposepadrão, você estará seguro. Mas eu correr através de alguns módulos de interoperabilidade que implementam IDispose. A chave aqui é para chamar Marshal.ReleaseCOMObjectquando você está feito com ele. Os objectos COM ainda usar a contagem de referência COM padrão.

Respondeu 07/08/2008 em 14:17
fonte usuário

votos
6

Eu encontrei .Net Memória Profiler uma boa ajuda quando encontrar vazamentos de memória em .Net. Não é gratuito como o Microsoft CLR Profiler, mas é mais rápido e mais direto ao ponto, na minha opinião. UMA

Respondeu 20/08/2008 em 19:39
fonte usuário

votos
1

Uma definição é: Não é possível para liberar memória inacessível, que não pode mais ser alocada para novo processo durante a execução do processo de alocação. Ela pode na sua maioria ser curado utilizando técnicas de GC ou detectado por ferramentas automatizadas.

Para mais informações, visite http://all-about-java-and-weblogic-server.blogspot.in/2014/01/what-is-memory-leak-in-java.html .

Respondeu 27/08/2014 em 16:22
fonte usuário

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