Como você detecta / evita vazamentos de memória no seu código (não gerenciado)? [fechadas]

125

No código C / C ++ não gerenciado, quais são as práticas recomendadas para detectar vazamentos de memória? E diretrizes de codificação para evitar? (Como se fosse assim tão simples;)

Usamos um pouco de maneira boba no passado: ter um incremento no contador para cada chamada de alocação de memória e decremento durante a liberação. No final do programa, o valor do contador deve ser zero.

Eu sei que essa não é uma ótima maneira e existem algumas capturas. (Por exemplo, se você estiver liberando memória que foi alocada por uma chamada de API da plataforma, sua contagem de alocação não corresponderá exatamente à sua contagem de liberação. Obviamente, incrementamos o contador ao chamar as chamadas de API que alocam memória).

Espero suas experiências, sugestões e talvez algumas referências a ferramentas que simplificam isso.

prakash
fonte
Em termos de evitar vazamentos o seguinte post tem alguns conselhos: http://stackoverflow.com/questions/27492/c-memory-management
tonylo
Eu usei este com o visual studio para detectar vazamentos de mem. codeproject.com/KB/applications/visualleakdetector.aspx
tiboo
1
você searh valgrin (para Linux) ou Deleaker (para Windows), também olhar detector de vazamento visuais ...
John Smith
para encontrar vazamentos de memória confira aqui: theunixshell.blogspot.com/2013/11/...
Vijay

Respostas:

78

Se o seu código C / C ++ é portátil para * nix, poucas coisas são melhores que o Valgrind .

Jordi Bunster
fonte
1
O Valgrind também agora funciona no OS X, portanto o Linux não é sua única opção.
Michael Anderson
1
Valgrind para Linux (e OS X). Se você usa windose - deleaker - o melhor de tudo!
John Smith
@JordiBunster: Nice! Mas baseado em tempo de execução. Com uma grande base de código (escrita em C em maiúsculas e minúsculas), você testará principalmente seu programa da maneira como ele foi projetado. Um invasor pode milhares de horas necessárias para ler o código, a fim de encontrar uma exploração de vazamento de memória. Eu esperava uma ferramenta automatizada para análise de código-fonte semelhante à existente para JavaScript.
user2284570
65

Se você estiver usando o Visual Studio, a Microsoft fornecerá algumas funções úteis para detectar e depurar vazamentos de memória.

Gostaria de começar com este artigo: https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.140).aspx

Aqui está o rápido resumo desses artigos. Primeiro, inclua estes cabeçalhos:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

Então você precisa chamar isso quando o seu programa sair:

_CrtDumpMemoryLeaks();

Como alternativa, se o seu programa não sair sempre no mesmo local, você pode chamar isso no início do programa:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

Agora, quando o programa sair, todas as alocações que não foram liberadas serão impressas na Janela de Saída, juntamente com o arquivo em que foram alocadas e a ocorrência da alocação.

Essa estratégia funciona para a maioria dos programas. No entanto, torna-se difícil ou impossível em certos casos. O uso de bibliotecas de terceiros que fazem alguma inicialização na inicialização pode fazer com que outros objetos apareçam no despejo de memória e dificultar o rastreamento de seus vazamentos. Além disso, se alguma de suas classes tiver membros com o mesmo nome de qualquer uma das rotinas de alocação de memória (como malloc), as macros de depuração do CRT causarão problemas.

Existem outras técnicas explicadas no link do MSDN mencionado acima que também podem ser usadas.

Dusty Campbell
fonte
Uma observação sobre esse método: parece que isso só funciona se você estiver usando C puro com malloc e free. O relatório detalhado que inclui números de linha não será criado se você estiver usando o novo e o apagamento do c ++.
Zach
2
@Zach: na verdade, você também pode fazer com que isso funcione (para qualquer código que você mesmo compile) - veja a resposta aceita em social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/…
Roman Starkov
Isso funcionará também no modo de liberação?
JV
1
@ user3152463 Não. De acordo com a documentação, ele funcionará apenas para a compilação de depuração: msdn.microsoft.com/en-us/library/e5ewb1h3(v=vs.71).aspx
Dusty Campbell
Esta linha está incorreta: #define CRTDBG_MAP_ALLOC Deveria ser: #define _CRTDBG_MAP_ALLOC
Fallso
37

Em C ++: use RAII. Ponteiros inteligentes gostam std::unique_ptr, std::shared_ptr, std::weak_ptrsão seus amigos.

Leon Timmermans
fonte
1
e std: vector é um ótimo substituto para quando matrizes (buffers) são desalocadas na mesma função em que são alocadas.
KJAWolf 30/09/08
4
Pelo menos std :: auto_ptr e boost :: shared_ptr ainda são suscetíveis a vazamentos.
Jasper Bekkers
5
Somente se você usá-los incorretamente, embora eu deva admitir que para std :: auto_ptr usá-lo incorretamente é bastante fácil.
Leon Timmermans
2
Embora este seja um bom conselho para os padrões de codificação, ele não responde à pergunta. Mesmo o uso do shared_ptr pode levar a vazamentos com dependências circulares. E você pode ter "vazamentos" com estratégias ilimitadas de armazenamento em cache, que se aplicam até a idiomas coletados pelo lixo.
CashCow
@ CashCow: você está correto. Embora eu ainda não tenha visto isso na prática, é provavelmente porque os estou usando com moderação. Para citar a resposta abaixo, "Use ponteiros somente quando for absolutamente necessário".
Leon Timmermans
28

Como desenvolvedor de C ++, aqui estão algumas diretrizes:

  1. Use ponteiros somente quando for absolutamente necessário
  2. Se você precisar de um ponteiro, verifique novamente se um SmartPointer é uma possibilidade
  3. Use o padrão GRASP Creator .

Quanto à detecção de vazamentos de memória pessoalmente, sempre usei o Visual Leak Detector e acho muito útil.

Huppie
fonte
2
O Visual Leak Detectore mudou-se para o novo site vld.codeplex.com
KindDragon
O VLD é um detector de vazamento MUITO bom - eu o recomendo totalmente para todos que usam o VC ++
Javid
1
+1 para o ponto 1. Isso é absolutamente fundamental. Infelizmente, parece-me que algumas das maiores bibliotecas "C ++" tendem a evitar a alocação de pilha e / ou RAII em favor do Pointers Everywhere, geralmente sem motivo aparente. Então, eles acabam sendo 'C com Classes', não C ++ real.
Underscore_d
16

Eu uso o DevStudio há muitos anos e sempre me surpreende quantos programadores não sabem sobre as ferramentas de análise de memória disponíveis nas bibliotecas de tempo de execução de depuração. Aqui estão alguns links para começar:

Rastreando solicitações de alocação de heap - especificamente a seção Números de solicitação de alocação exclusivos

_CrtSetDbgFlag

_CrtSetBreakAlloc

Obviamente, se você não estiver usando o DevStudio, isso não será particularmente útil.

Skizz
fonte
10

Estou surpreso que ninguém tenha mencionado o DebugDiag para Windows OS.
Ele funciona em versões de lançamento e até no site do cliente.
(Você só precisa manter os PDBs da versão de lançamento e configurar o DebugDiag para usar o servidor de símbolos públicos da Microsoft)

Tal
fonte
3
O link não funciona mais, tente aqui para obter a documentação: support.microsoft.com/kb/2580960 e aqui para fazer o download: microsoft.com/en-us/download/details.aspx?id=26798
JPaget
7

O Visual Leak Detector é uma ferramenta muito boa, embora não suporte as chamadas nos tempos de execução do VC9 (MSVCR90D.DLL, por exemplo).

Hernán
fonte
1
Esta ferramenta é realmente perfeita! Isso evita o problema de usar o _CrtDumpMemoryLeaks (); e amigos, conforme descrito no MSDN. Apenas um inclui e expõe tudo! Até funciona em antigas bibliotecas C!
m_pGladiator
A nova versão (para VS2013) está aqui: vld.codeplex.com
Dženan
7

O Microsoft VC ++ no modo de depuração mostra vazamentos de memória, embora não mostre onde estão os vazamentos.

Se você estiver usando C ++ você sempre pode evitar o uso de novo explicitamente: você tem vector, string, auto_ptr(pré C ++ 11; substituído por unique_ptrem C ++ 11), unique_ptr(C ++ 11) eshared_ptr (C ++ 11) em seu arsenal.

Quando new for inevitável, tente ocultá-lo em um construtor (e ocultar delete em um destruidor); o mesmo funciona para APIs de terceiros.

Serge
fonte
1
e não se esqueça a regra de 3 ou de 5 em seguida
Humam Helfawi
4

Existem várias bibliotecas "malloc" substitutas por aí que permitem que você chame uma função no final e ela informa sobre toda a memória não liberada e, em muitos casos, quem a mallocou (ou foi recém-introduzida) em primeiro lugar .

Paul Tomblin
fonte
4

Se você estiver usando o MS VC ++, recomendo esta ferramenta gratuita no codeproject: leakfinder de Jochen Kalmbach.

Você simplesmente adiciona a classe ao seu projeto e chama

InitAllocCheck(ACOutput_XML)
DeInitAllocCheck()

antes e depois do código que você deseja verificar se há vazamentos.

Depois de criar e executar o código, Jochen fornece uma ferramenta GUI pura, na qual é possível carregar o arquivo .xmlleaks resultante e navegar pela pilha de chamadas onde cada vazamento foi gerado para procurar a linha de código incorreta.

O PurifyPlus da Rational (agora de propriedade da IBM) ilustra vazamentos de maneira semelhante, mas acho a ferramenta de rastreador de vazamentos realmente mais fácil de usar, com o bônus de não custar vários milhares de dólares!

John Sibly
fonte
1
Eu verifiquei o detector de vazamentos e parece bom, mas apenas para sua informação, ele não funcionará como está para x64 porque contém montagem em linha.
Zach
3

Eu nunca o usei, mas meus amigos C me dizem Purify .

Iain Holder
fonte
3

Se você estiver usando o Visual Studio, pode valer a pena examinar o Verificador de limites . Não é gratuito, mas tem sido incrivelmente útil para encontrar vazamentos no meu código. Ele não apenas faz vazamentos de memória, mas também vazamentos de recursos GDI, erros de uso do WinAPI e outras coisas. Ele até mostra onde a memória vazada foi inicializada, facilitando a localização do vazamento.

Herms
fonte
2

Eu acho que não há uma resposta fácil para essa pergunta. Como você realmente pode abordar esta solução depende de seus requisitos. Você precisa de uma solução multiplataforma? Você está usando new / delete ou malloc / free (ou ambos)? Você está realmente procurando apenas "vazamentos" ou deseja uma melhor proteção, como a detecção de excedentes de buffer (ou underruns)?

Se você estiver trabalhando no lado do Windows, as bibliotecas do MS debug runtime têm algumas funcionalidades básicas de detecção de depuração e, como outra já apontou, existem vários wrappers que podem ser incluídos na sua fonte para ajudar na detecção de vazamentos. Encontrar um pacote que possa funcionar com new / delete e malloc / free obviamente oferece mais flexibilidade.

Não sei o suficiente sobre o lado unix para fornecer ajuda, embora mais uma vez outros o tenham.

Mas, além da detecção de vazamento, existe a noção de detecção de corrupção de memória via saturação de buffer (ou saturação). Esse tipo de funcionalidade de depuração é mais difícil que a simples detecção de vazamentos. Esse tipo de sistema também é mais complicado se você estiver trabalhando com objetos C ++, pois as classes polimórficas podem ser excluídas de várias maneiras, causando dificuldade na determinação do verdadeiro ponteiro base que está sendo excluído. Não conheço um bom sistema "gratuito" que faça uma proteção decente para excedentes. nós escrevemos um sistema (multiplataforma) e achamos bastante desafiador.

Marca
fonte
2

Eu gostaria de oferecer algo que usei em alguns momentos no passado: um verificador de vazamentos rudimentar, que é no nível da fonte e bastante automático. Estou denunciando isso por três razões:

  1. Você pode achar util.

  2. Embora seja um pouco errado, não deixo isso me envergonhar.

  3. Mesmo que esteja vinculado a alguns ganchos win32, isso deve ser fácil de aliviar.

Há coisas que você deve ter cuidado ao usá-la: não faça nada que precise se apoiar new código subjacente, tenha cuidado com os avisos sobre casos que podem faltar no topo do leakcheck.cpp, perceba que se você ligar (e corrija quaisquer problemas com) o código que faz o despejo de imagens, você pode gerar um arquivo enorme.

O design visa permitir que você ligue e desligue o verificador sem recompilar tudo o que inclui seu cabeçalho. Inclua leakcheck.h onde deseja rastrear a verificação e reconstruir uma vez. Depois disso, compile leakcheck.cpp com ou sem LEAKCHECK # define e, em seguida, vincule novamente para ativá-lo e desativá-lo. A inclusão de unleakcheck.h o desativará localmente em um arquivo. Duas macros são fornecidas: CLEARALLOCINFO () evitará relatar o mesmo arquivo e linha de forma inadequada quando você percorrer o código de alocação que não incluiu leakcheck.h. ALLOCFENCE () apenas descarta uma linha no relatório gerado sem fazer nenhuma alocação.

Novamente, lembre-se de que não utilizo isso há algum tempo e você pode precisar trabalhar um pouco. Estou falando disso para ilustrar a ideia. Se houver interesse suficiente, eu estaria disposto a elaborar um exemplo, atualizando o código no processo e substituindo o conteúdo da URL a seguir por algo mais agradável que inclua uma lista decentemente colorida de sintaxe.

Você pode encontrá-lo aqui: http://www.cse.ucsd.edu/~tkammeye/leakcheck.html

Thomas Kammeyer
fonte
2

Para Linux: tente Google Perftools

Existem muitas ferramentas que fazem contagem similar de alocação / livre, os profissionais do Goolge Perftools:

  • Muito rápido (em comparação com o valgrind: muito rápido)
  • Vem com boa exibição gráfica de resultados
  • Tem outros recursos úteis: criação de perfil de CPU, criação de perfil de uso de memória ...
Weidenrinde
fonte
2

A melhor defesa contra vazamentos é uma estrutura de programa que minimiza o uso de malloc. Isso não é apenas bom do ponto de vista de programação, mas também melhora o desempenho e a capacidade de manutenção. Eu não estou falando sobre o uso de outras coisas no lugar do malloc, mas em termos de reutilização de objetos e de manter abas muito explícitas em todos os objetos que estão sendo passados ​​ao invés de alocar à vontade, como costuma ser usado em idiomas com coletores de lixo como Java.

Por exemplo, um programa em que trabalho tem um monte de objetos de quadro que representam dados de imagem. Cada objeto de quadro possui sub-dados, liberados pelo destruidor do quadro. O programa mantém uma lista de todos os quadros alocados e, quando precisar de um novo, verifica uma lista de objetos de quadro não utilizados para ver se é possível reutilizar um existente, em vez de alocar um novo. No desligamento, ele apenas percorre a lista, liberando tudo.

Dark Shikari
fonte
2

Eu recomendaria o uso do Memory Validator partir da verificação do software. Essa ferramenta provou ser uma ajuda inestimável para me ajudar a rastrear vazamentos de memória e melhorar o gerenciamento de memória dos aplicativos em que estou trabalhando.

Uma ferramenta muito completa e rápida.

Fabien Hure
fonte
O Validador de memória também fornece o nome do arquivo e o número da linha para C # que chama seu código nativo. A versão x64 está na versão beta
Stephen Kellett
2

Você está contando as alocações e liberações interpolando suas próprias funções syscall que gravam as chamadas e depois passam a chamada para a função real?

Essa é a única maneira de controlar as chamadas originadas no código que você não escreveu.

Dê uma olhada na página de manual do ld.so. Ou ld.so.1 em alguns sistemas.

Faça também o Google LD_PRELOAD e você encontrará alguns artigos interessantes explicando a técnica no site www.itworld.com.

Rob Wells
fonte
1

Pelo menos para o MS VC ++, a biblioteca C Runtime possui várias funções que eu achei úteis no passado. Verifique a ajuda do MSDN para as _Crt*funções.

Dan Shield
fonte
1

O mmgr de Paul Nettle é uma das minhas ferramentas favoritas de longa data. Você inclui mmgr.h nos arquivos de origem, define TEST_MEMORY e ele fornece um arquivo de texto cheio de problemas de memória que ocorreram durante a execução do seu aplicativo.

Josh Matthews
fonte
1

Diretriz geral de codificação:

  • Os recursos devem ser desalocados na mesma "camada" (função / classe / biblioteca) em que estão alocados.
  • Se isso não for possível, tente usar uma desalocação automática (aumentar o ponteiro compartilhado ...)
Weidenrinde
fonte
1

As ferramentas de depuração de memória valem seu peso em ouro, mas, ao longo dos anos, descobri que duas idéias simples podem ser usadas para impedir que a maioria dos vazamentos de memória / recursos seja codificada em primeiro lugar.

  1. Escreva o código de liberação imediatamente após escrever o código de aquisição para os recursos que você deseja alocar. Com esse método, é mais difícil "esquecer" e, em certo sentido, obriga a pensar seriamente no ciclo de vida dos recursos sendo usados ​​antecipadamente, e não como um aparte.

  2. Use o retorno o mais moderadamente possível. O que é alocado deve ser liberado apenas em um local, se possível. O caminho condicional entre a aquisição do recurso e a liberação deve ser projetado para ser o mais simples e óbvio possível.

Einstein
fonte
1

No topo desta lista (quando a li) estava o valgrind. O Valgrind é excelente se você conseguir reproduzir o vazamento em um sistema de teste. Eu usei com grande sucesso.

E se você acabou de perceber que o sistema de produção está vazando no momento e você não tem idéia de como reproduzi-lo em teste? Alguma evidência do que está errado é capturada no estado desse sistema de produção e pode ser suficiente para fornecer uma visão de onde está o problema, para que você possa reproduzi-lo.

É aí que a amostra de Monte Carlo entra em cena. Leia o artigo do blog de Raymond Chen, “O jeito do pobre homem de identificar vazamentos de memória” e confira minha implementação (assume o Linux, testado apenas em x86 e x86-64)

http://github.com/tialaramex/leakdice/tree/master

tialaramex
fonte
1

Trabalhando no sistema operacional de telefones celulares da Motorola, invadimos a biblioteca de alocação de memória para observar todas as alocações de memória. Isso ajudou a encontrar muitos problemas com alocações de memória. Como a prevenção é melhor do que remediar , eu recomendaria o uso de ferramentas de análise estática como Klockwork ou PC-Lint

aku
fonte
splint é um novo substituto para o fiapo.
Mark Kegel
@ user14788: O produto PC-Lint da Gimpel é muito mais moderno que o antigo Unix lint. Ele tem muitas verificações específicas para C ++, que o afaik splint não possui. Veja o link na resposta (que renomei de Lint para PC-Lint).
Dan
0

Valgrind é uma boa opção para Linux. No MacOS X, você pode ativar a biblioteca MallocDebug, que possui várias opções para depurar problemas de alocação de memória (consulte a página de manual do malloc, a seção "AMBIENTE" possui os detalhes relevantes). O OS X SDK também inclui uma ferramenta chamada MallocDebug (geralmente instalada em / Developer / Applications / Performance Tools /) que pode ajudá-lo a monitorar o uso e os vazamentos.

jbl
fonte
0

Detectar:

Depurar CRT

Evitar:

Ponteiros inteligentes, boehm GC

DrPizza
fonte
0

Uma boa substituição de malloc, calloc e reallloc é o rmdebug, é bem simples de usar. É muito mais rápido fazer valgrind, para que você possa testar seu código extensivamente. É claro que ele tem algumas desvantagens, uma vez que você encontrou um vazamento, provavelmente ainda precisará usar o valgrind para descobrir onde o vazamento aparece e você só pode testar mallocs diretamente. Se uma lib vazar porque você a usa incorretamente, o rmdebug não a encontrará.

http://www.hexco.de/rmdebug/

quinmars
fonte
0

A maioria dos criadores de perfil de memória desacelera meu aplicativo Windows grande e complexo até o ponto em que os resultados são inúteis. Há uma ferramenta que funciona bem para encontrar vazamentos no meu aplicativo: UMDH - http://msdn.microsoft.com/en-us/library/ff560206%28VS.85%29.aspx

Sean
fonte
Não vejo por que a desaceleração torna os resultados inúteis. Certamente a memória vazada está vazando, independentemente da velocidade com que o programa é executado. O objetivo dessas ferramentas é encontrar vazamentos; então, onde está o problema? Ele foi executado tão lentamente que você não conseguiu fisicamente cobrir todos os caminhos de código para criá-los?
underscore_d
-1

Mtrace parece ser o padrão embutido no linux. Os passos são:

  1. configure a variável de ambiente MALLOC_TRACE no bash
    MALLOC_TRACE = / tmp / mtrace.dat
    export MALLOC_TRACE;
  2. Adicione #include <mcheck.h> ao topo do seu arquivo de origem principal
  3. Adicione mtrace (); no início de main e muntrace ();na parte inferior (antes da declaração de retorno)
  4. compile seu programa com a opção -g para obter informações sobre depuração
  5. execute seu programa
  6. exibir informações de vazamento com
    mtrace your_prog_exe_name /tmp/mtrace.dat
    (Eu tive que instalar o script mtrace perl primeiro no meu sistema fedora com o yum install glibc_utils   )
rots paperhorse
fonte
mtrace não é super útil para C ++
Erin