Eu sou um programador de C ++ na plataforma Windows. Estou usando o Visual Studio 2008.
Normalmente, acabo no código com vazamentos de memória.
Normalmente, encontro o vazamento de memória inspecionando o código, mas é complicado e nem sempre é uma boa abordagem.
Como não posso pagar por uma ferramenta de detecção de vazamento de memória paga, queria que vocês sugerissem as melhores maneiras possíveis para evitar vazamentos de memória.
- Quero saber como o programador pode encontrar vazamentos de memória.
- Existe algum padrão ou procedimento que você deve seguir para garantir que não haja vazamento de memória no programa?
c++
memory-leaks
Chris_vr
fonte
fonte
Respostas:
Instruções
Coisas que você precisa
1
Compreenda os conceitos básicos do operador. O operador C ++
new
aloca memória heap. Odelete
operador libera memória de pilha. Para cadanew
, você deve usar umdelete
para liberar a mesma memória que alocou:2
Realoque a memória apenas se você tiver excluído. No código abaixo,
str
adquire um novo endereço com a segunda alocação. O primeiro endereço é perdido irremediavelmente e os 30 bytes que ele apontou. Agora eles são impossíveis de liberar e você tem um vazamento de memória:3
Assista as atribuições dos ponteiros. Toda variável dinâmica (memória alocada na pilha) precisa ser associada a um ponteiro. Quando uma variável dinâmica é desassociada do (s) ponteiro (s), torna-se impossível apagar. Novamente, isso resulta em um vazamento de memória:
4
Tenha cuidado com os ponteiros locais. Um ponteiro que você declara em uma função é alocado na pilha, mas a variável dinâmica para a qual ele aponta é alocada no heap. Se você não excluí-lo, ele persistirá depois que o programa sair da função:
5
Preste atenção nas chaves depois de "excluir". Use
delete
por si só para liberar um único objeto. Usedelete []
com colchetes para liberar uma matriz de heap. Não faça algo assim:6
Se o vazamento ainda for permitido - eu geralmente o procuro com deleaker (verifique aqui: http://deleaker.com ).
fonte
someFunction("some parameter")
tenho que excluir"some parameter"
nosomeFunction
, após a chamada de função, ou eles são automaticamente excluídos?Você pode usar algumas técnicas no seu código para detectar vazamento de memória. A maneira mais comum e mais fácil de detectar é: defina uma macro, DEBUG_NEW, e use-a, juntamente com macros predefinidas como
__FILE__
e__LINE__
para localizar o vazamento de memória no seu código. Essas macros predefinidas informam o número do arquivo e da linha de vazamentos de memória.DEBUG_NEW é apenas um MACRO que geralmente é definido como:
Para que, onde quer que você use
new
, ele também possa acompanhar o número do arquivo e da linha que pode ser usado para localizar vazamento de memória no seu programa.E
__FILE__
,__LINE__
são macros predefinidas que avaliam o nome do arquivo e o número da linha, respectivamente, onde você os usa!Leia o artigo a seguir, que explica a técnica de usar DEBUG_NEW com outras macros interessantes, muito bem:
Um detector de vazamento de memória de plataforma cruzada
Da Wikpedia ,
fonte
#define
vai atrapalhar a sobrecargaoperator new
e gerar erros do compilador. Mesmo se você conseguir superar isso, as funções sobrecarregadas ainda não serão abordadas. Embora a técnica seja boa, às vezes precisa de muitas alterações de código.auto_ptr
não funcionará com contêineres padrão, comostd::vector
,std::list
etc. Veja isto: stackoverflow.com/questions/111478/…operator new
e quais são essas versões que você está usando?Existem algumas técnicas de programação conhecidas que ajudarão você a minimizar o risco de obter vazamentos de memória em primeira mão:
new
edelete
sempre em pares, e certifique-se o código de alocação / desalocação é chamado paresvector<T> t
sempre que possível em vez deT* t = new T[size]
fonte
Valgrind http://valgrind.org/
e
GDB http://www.gnu.org/software/gdb/
fonte
gflags
utilitário para ativar rastreamentos de pilha no modo de usuário.UMDH
para tirar vários instantâneos da memória do seu programa. Tire um instantâneo antes que a memória seja alocada e tire um segundo instantâneo depois de um ponto em que você acredita que seu programa perdeu memória. Você pode adicionar pausas ou avisos em seu programa para ter a chance de executarUMDH
e tirar os instantâneos.UMDH
novamente, desta vez no modo que faz uma diferença entre os dois instantâneos. Em seguida, ele gera um relatório contendo as pilhas de chamadas com suspeita de vazamento de memória.gflags
configurações anteriores quando terminar.UMDH
fornecerá mais informações do que o heap de depuração do CRT, pois ele está assistindo alocações de memória em todo o processo; pode até dizer se estão vazando componentes de terceiros.fonte
A execução de "Valgrind" pode:
1) Ajude a identificar vazamentos de memória - mostre quantos vazamentos de memória você tem e aponte para as linhas no código em que a memória vazada foi alocada.
2) Apontar tentativas erradas de liberar memória (por exemplo, chamada incorreta de
delete
)Instruções para usar "Valgrind"
1) Obtenha valgrind aqui .
2) Compile seu código com a
-g
bandeira3) Na sua shell, execute:
Onde "myprog" é o seu programa compilado e
arg1
,arg2
argumentos do seu programa.4) O resultado é uma lista de chamadas para
malloc
/new
que não tiveram chamadas subsequentes para exclusão gratuita.Por exemplo:
Informa em qual linha o
malloc
(que não foi liberado) foi chamado.Conforme indicado por outras pessoas, verifique se você tem uma chamada
new
/ para cadamalloc
chamadadelete
/free
.fonte
Se você usa o gcc, há o gprof disponível.
Alguns usam ferramentas, outros fazem o que você faz, também através da revisão de código por pares
Para mim: sempre que crio objetos alocados dinamicamente, sempre coloco o código de liberação depois e preencho o código entre eles. Isso seria bom se você tiver certeza de que não haverá exceções no código entre elas. Caso contrário, utilizo try-finally (não uso C ++ com freqüência).
fonte
No visual studio, existe um detector interno para vazamento de memória chamado C Runtime Library. Quando o programa sair após o retorno da função principal, o CRT verificará o heap de depuração do seu aplicativo. se você ainda tiver algum bloco alocado no heap de depuração, haverá vazamento de memória.
Este fórum discute algumas maneiras de evitar vazamento de memória em C / C ++.
fonte
Pesquise ocorrências de seu código
new
e verifique se todas elas ocorrem em um construtor com uma exclusão correspondente em um destruidor. Certifique-se de que esta seja a única operação de lançamento possível nesse construtor. Uma maneira simples de fazer isso é agrupar todos os ponteirosstd::auto_ptr
, ouboost::scoped_ptr
(dependendo se você precisa ou não mover a semântica). Para todo o código futuro, verifique se todos os recursos pertencem a um objeto que limpa o recurso em seu destruidor. Se você precisar mover semântica, poderá atualizar para um compilador que ofereça suporte a referências de valor-r (acredito o VS2010) e criar construtores de movimentação. Se você não quiser fazer isso, poderá usar uma variedade de técnicas complicadas que envolvem o uso consciente de swap ou experimentar a biblioteca Boost.Move.fonte
scope_ptr
s, e cada um for inicializado individualmente, todos os que foram construídos com êxito excluirão seus ponteiros, e os outros ainda não estarão mantendo ponteiros na memória alocada. Darei um exemplo em poucas horas quando chegar em casa do trabalho.Você pode usar a ferramenta Valgrind para detectar vazamentos de memória.
Além disso, para encontrar o vazamento em uma função específica, use exit (0) no final da função e execute-a com Valgrind
fonte
Uma pesquisa com verificadores automáticos de vazamento de memória
Nesta resposta, comparo vários verificadores de vazamento de memória em um exemplo simples e fácil de entender.
Antes de qualquer coisa, consulte esta enorme tabela no wiki do ASan que compara todas as ferramentas conhecidas pelo homem: https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06210f759fec97066888e5f27c7e722832b0924
O exemplo analisado será:
main.c
GitHub upstream .
Vamos tentar ver com que clareza as diferentes ferramentas nos apontam para os vazamentos.
tcmalloc de gperftools pelo Google
https://github.com/gperftools/gperftools
Uso no Ubuntu 19.04:
A saída da execução do programa contém a análise de vazamento de memória:
e a saída de
google-pprof
contém a análise de uso de heap:A saída aponta para dois dos três vazamentos:
Não sei por que o terceiro não apareceu
De qualquer forma, quando geralmente quando algo vaza, isso acontece muitas vezes, e quando eu o usei em um projeto real, acabei sendo apontado para a função vazamento com muita facilidade.
Conforme mencionado na própria saída, isso gera uma desaceleração significativa na execução.
Mais documentação em:
Veja também: Como usar o TCMalloc?
Testado no Ubuntu 19.04, google-perftools 2.5-2.
Sanitizer de endereço (ASan) também pelo Google
https://github.com/google/sanitizers
Mencionado anteriormente em: Como encontrar vazamento de memória em um código / projeto C ++? TODO vs tcmalloc.
Isso já está integrado ao GCC, então você pode:
e saídas de execução:
que identifica claramente todos os vazamentos. Agradável!
O ASan também pode fazer outras verificações interessantes, como gravações fora dos limites: Smashing de pilha detectado
Testado no Ubuntu 19.04, GCC 8.3.0.
Valgrind
http://www.valgrind.org/
Mencionado anteriormente em: https://stackoverflow.com/a/37661630/895245
Uso:
Resultado:
Então, mais uma vez, todos os vazamentos foram detectados.
Veja também: Como uso o valgrind para encontrar vazamentos de memória?
Testado no Ubuntu 19.04, valgrind 3.14.0.
fonte
O Visual Leak Detector (VLD) é um sistema de detecção de vazamento de memória livre, robusto e de código aberto para o Visual C ++.
Se você tiver apenas despejos de memória, poderá usar o
!heap -l
comando Windbg , ele detectará blocos de heap vazados. É melhor abrir a opção gflags: “Criar banco de dados de rastreamento de pilha no modo de usuário”, e você verá a pilha de chamadas de alocação de memória.fonte
O MTuner é uma ferramenta gratuita de análise de perfil, detecção e análise de vazamentos de memória multiplataforma que suporta os compiladores MSVC, GCC e Clang. Características incluem:
Os usuários podem criar um perfil de qualquer plataforma de segmentação de software com compiladores cruzados GCC ou Clang. O MTuner vem com suporte embutido para plataformas Windows, PlayStation 4 e PlayStation 3.
fonte
No Windows, você pode usar o heap de depuração CRT .
Sim, não use o gerenciamento manual de memória (se você ligar
delete
oudelete[]
manualmente, estará fazendo errado). Use RAII e ponteiros inteligentes, limite as alocações de heap ao mínimo absoluto (na maioria das vezes, variáveis automáticas serão suficientes).fonte
Respondendo à segunda parte da sua pergunta,
Sim existe. E essa é uma das principais diferenças entre C e C ++.
No C ++, você nunca deve chamar
new
oudelete
no seu código de usuário. RAII é uma técnica muito usada, que resolve praticamente o problema de gerenciamento de recursos. Todo recurso em seu programa (um recurso é qualquer coisa que precise ser adquirida e, posteriormente, liberada: identificadores de arquivo, soquetes de rede, conexões com bancos de dados, mas também alocações simples de memória e, em alguns casos, pares de chamadas de API (BeginX ( ) / EndX (), LockY (), UnlockY ()), devem ser agrupados em uma classe, em que:new
se o recurso é uma alocação de memroy)Essa classe é instanciada localmente, na pilha ou como membro da classe, e não chamando
new
e armazenando um ponteiro.Você geralmente não precisa definir essas classes por conta própria. Os contêineres da biblioteca padrão também se comportam dessa maneira, para que qualquer objeto armazenado em um
std::vector
arquivo seja liberado quando o vetor for destruído. Então, novamente, não armazene um ponteiro no contêiner (o que exigiria que você chamassenew
edelete
), mas o próprio objeto (que fornece gerenciamento de memória gratuitamente ). Da mesma forma, as classes de ponteiros inteligentes podem ser usadas para quebrar facilmente objetos que precisam ser alocadosnew
e controlar sua vida útil.Isso significa que, quando o objeto sai do escopo, ele é destruído automaticamente e seu recurso liberado e limpo.
Se você fizer isso de forma consistente em todo o código, você simplesmente não terá vazamentos de memória. Tudo o que pode vazar é vinculado a um destruidor que é garantido para ser chamado quando o controle sai do escopo em que o objeto foi declarado.
fonte
AddressSanitizer (ASan) é um detector de erro de memória rápido. Ele encontra erros de estouro de uso após livre e {heap, stack, global} -uffer em programas C / C ++. Encontra:
Esta ferramenta é muito rápida. A desaceleração média do programa instrumentado é ~ 2x.
fonte
Além das ferramentas e métodos fornecidos nas outras respostas, ferramentas de análise de código estático podem ser usadas para detectar vazamentos de memória (e outros problemas também). Uma ferramenta gratuita e robusta é o Cppcheck. Mas existem muitas outras ferramentas disponíveis. A Wikipedia possui uma lista de ferramentas estáticas de análise de código.
fonte
Verifique se toda a memória heap foi liberada com êxito. Não há necessidade se você nunca alocar memória no heap. Se o fizer, conte o número de vezes que você armazena a memória e conte o número de vezes que libera memória.
fonte
Nem "novo" nem "excluir" devem ser usados no código do aplicativo. Em vez disso, crie um novo tipo que use o idioma gerente / trabalhador, no qual a classe gerente aloca e libera memória e encaminha todas as outras operações para o objeto trabalhador.
Infelizmente, isso é mais trabalhoso do que deveria, porque o C ++ não possui sobrecarga de "operator". É ainda mais trabalho na presença de polimorfismo.
Mas isso vale a pena, porque você nunca precisa se preocupar com vazamentos de memória, o que significa que você nem precisa procurá-los.
fonte