Como encontrar vazamento de memória em um código / projeto C ++?

180

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.

  1. Quero saber como o programador pode encontrar vazamentos de memória.
  2. Existe algum padrão ou procedimento que você deve seguir para garantir que não haja vazamento de memória no programa?
Chris_vr
fonte
29
"Normalmente, acabo no código com vazamento de memória." Se você usar variáveis ​​automáticas, contêineres e ponteiros inteligentes (e seguir as práticas recomendadas para usar ponteiros inteligentes), vazamentos de memória deverão ser extremamente raros. Lembre-se, em quase todos os casos, você deve usar o gerenciamento automático de recursos .
James McNellis
Duplica os problemas cobertos por várias perguntas, como stackoverflow.com/questions/1502799/… e stackoverflow.com/questions/2820223/…
HostileFork diz que não confia em
1
@Hostile Fork: "como se pode evitar que geralmente acabe em código com vazamentos de memória" não é coberto por essas respostas.
Doc Brown
2
@Doc Brown: Não tive vontade de procurar isso também, mas está tudo coberto em outro lugar, como stackoverflow.com/questions/45627/…
HostileFork diz que não confia em
1
Detector de vazamento DIY: você pode colocar um código suspeito em um loop infinito e abrir um gerenciador de tarefas, normalmente até um pequeno vazamento enche a memória em segundos ou minutos (isso depende da complexidade do código e da CPU). Se isso não acontecer, esse código provavelmente não está vazando.
Olá Mundo

Respostas:

270

Instruções

Coisas que você precisa

  • Proficiência em C ++
  • Compilador C ++
  • Depurador e outras ferramentas de software investigativas

1

Compreenda os conceitos básicos do operador. O operador C ++ newaloca memória heap. O deleteoperador libera memória de pilha. Para cada new, você deve usar um deletepara liberar a mesma memória que alocou:

char* str = new char [30]; // Allocate 30 bytes to house a string.

delete [] str; // Clear those 30 bytes and make str point nowhere.

2

Realoque a memória apenas se você tiver excluído. No código abaixo, stradquire 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:

char* str = new char [30]; // Give str a memory address.

// delete [] str; // Remove the first comment marking in this line to correct.

str = new char [60]; /* Give str another memory address with
                                                    the first one gone forever.*/

delete [] str; // This deletes the 60 bytes, not just the first 30.

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:

char* str1 = new char [30];

char* str2 = new char [40];

strcpy(str1, "Memory leak");

str2 = str1; // Bad! Now the 40 bytes are impossible to free.

delete [] str2; // This deletes the 30 bytes.

delete [] str1; // Possible access violation. What a disaster!

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:

void Leak(int x){

char* p = new char [x];

// delete [] p; // Remove the first comment marking to correct.

}

5

Preste atenção nas chaves depois de "excluir". Use deletepor si só para liberar um único objeto. Use delete []com colchetes para liberar uma matriz de heap. Não faça algo assim:

char* one = new char;

delete [] one; // Wrong

char* many = new char [30];

delete many; // Wrong!

6

Se o vazamento ainda for permitido - eu geralmente o procuro com deleaker (verifique aqui: http://deleaker.com ).

John Smith
fonte
3
desculpe pelo comentário da pergunta, mas e os parâmetros de função sem ponteiros? someFunction("some parameter")tenho que excluir "some parameter"no someFunction, após a chamada de função, ou eles são automaticamente excluídos?
199696
1
obrigado pelo link para o Deleaker, esta é uma ferramenta realmente útil, com uma perfeita integração ao visual studio. Eu poderia economizar muito tempo usando. apontou-me para as linhas em que alocava memória e não a liberava. Ótimo. E é barato, comparado com outros localizadores de vazamento de memória que encontrei.
this.myself
@ john smith plz explica qual é a maneira correta de lidar com casos semelhantes ao caso 3; str2 = str1; // Ruim! Agora, os 40 bytes são impossíveis de liberar. como excluir str 1 então?
Nihar
1
E se usarmos o tipo de valor como char *, int, float, ... e estruturar como Vector, CString e não usarmos nenhum operador 'novo', isso não causará vazamento de memória, está certo?
123
Estou aqui apenas para dizer que não toquei em c ++ há quase 14 anos ... mas tenho orgulho de dizer que entendi e lembro de como fazer tudo isso graças a um livro em c ++ que ainda possuo e leio quando eu ' estou entediado com c #. Esse livro é o C ++ eficaz de Scott Mitchell. Deus, eu amei esse livro. Graças à Scott!
Jonh
33

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:

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

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 ,

Debug_new refere-se a uma técnica em C ++ para sobrecarregar e / ou redefinir o operador novo e a exclusão do operador para interceptar as chamadas de alocação e desalocação de memória e, portanto, depurar um programa para uso de memória. Geralmente envolve a definição de uma macro denominada DEBUG_NEW e faz com que new se torne algo como novo (_ FILE _, _ LINE _) para registrar as informações de arquivo / linha na alocação.O Microsoft Visual C ++ usa essa técnica em suas Microsoft Foundation Classes. Existem algumas maneiras de estender esse método para evitar o uso de redefinição de macro enquanto ainda é possível exibir as informações de arquivo / linha em algumas plataformas. Existem muitas limitações inerentes a esse método. Aplica-se apenas ao C ++ e não pode detectar vazamentos de memória por funções C como malloc. No entanto, pode ser muito simples de usar e também muito rápido, quando comparado a algumas soluções mais completas de depurador de memória.

Nawaz
fonte
4
isso #definevai atrapalhar a sobrecarga operator newe 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.
Iammilind
1
@iammilind: Claro, essa técnica não é uma solução completa para todos os problemas e certamente não é aplicável em todas as situações.
Nawaz
@ Chris_vr: auto_ptrnão funcionará com contêineres padrão, como std::vector, std::listetc. Veja isto: stackoverflow.com/questions/111478/…
Nawaz
OK fixe. ARQUIVO e linha são descritos. O que é operator newe quais são essas versões que você está usando?
14

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:

  • se você tem que fazer sua alocação de memória própria dinâmica, gravação newe deletesempre em pares, e certifique-se o código de alocação / desalocação é chamado pares
  • evite a alocação dinâmica de memória, se puder. Por exemplo, use vector<T> tsempre que possível em vez deT* t = new T[size]
  • use "ponteiros inteligentes" como ponteiros inteligentes de impulso ( http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm )
  • meu favorito pessoal: certifique-se de entender o conceito de propriedade de um ponteiro e, em qualquer lugar em que você use ponteiros, saiba qual entidade de código é o proprietário.
  • aprenda quais construtores / operadores de atribuição são criados automaticamente pelo compilador C ++ e o que isso significa se você tiver uma classe que possui um ponteiro (ou o que isso significa se você tiver uma classe que contenha um ponteiro para um objeto que não possui).
Doc Brown
fonte
Eu uso auto_pointer de um objeto, isso significa que ele excluirá todos os outros ponteiros de objetos de classe dentro dele.
7898 Chris_vr
@ Chris_vr: se você tiver uma pergunta específica sobre o auto_pointer, sugiro que faça uma nova pergunta, incluindo um exemplo.
Doc Brown
Muitas postagens me dizem que o vetor <> não garante que a memória seja liberada após a limpeza. Eu pessoalmente testei coisas de troca etc e cheguei à conclusão de que o vetor <> está vazando, especialmente quando usado dinamicamente. Não entendo como o vetor <> pode ser aconselhado sobre a alocação dinâmica do tipo faça você mesmo, usando 'novo' e limpeza corretamente. Nos meus programas incorporados, evito usar o vetor <> para coisas dinâmicas por causa de todos os vazamentos. Lá eu usar de novo ou std :: lista
Bart s
Eu digito um segundo comando por causa do número de caracteres. Infelizmente no meu c ++ incorporado eu tenho um c ++ antigo (98?) Que não tem shrink_to_fit em um vetor ... No entanto, o programa incorporado tem 100% de certeza de falha total ao ficar sem memória usando o vetor <> dinamicamente
bart s
8
  1. Faça o download das Ferramentas de Depuração para Windows .
  2. Use o gflagsutilitário para ativar rastreamentos de pilha no modo de usuário.
  3. Use UMDHpara 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 executar UMDHe tirar os instantâneos.
  4. Execute UMDHnovamente, 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.
  5. Restaure as gflagsconfigurações anteriores quando terminar.

UMDHfornecerá 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.

Aaron Klotz
fonte
1
Eu prefiro Deleaker e Valgrind em vez de profiler padrão
z0r1fan
8

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 -gbandeira

3) Na sua shell, execute:

valgrind --leak-check=yes myprog arg1 arg2

Onde "myprog" é o seu programa compilado e arg1, arg2argumentos do seu programa.

4) O resultado é uma lista de chamadas para malloc/ newque não tiveram chamadas subsequentes para exclusão gratuita.

Por exemplo:

==4230==    at 0x1B977DD0: malloc (vg_replace_malloc.c:136)

==4230==    by 0x804990F: main (example.c:6)

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 cada mallocchamada delete/ free.

Gal Nachmana
fonte
6

Se você usa o gcc, há o gprof disponível.

Eu queria saber como programador encontrar vazamento de memória

Alguns usam ferramentas, outros fazem o que você faz, também através da revisão de código por pares

Existe algum padrão ou procedimento que você deve seguir para garantir que não haja vazamento de memória no programa

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).

LeleDumbo
fonte
em algum momento, não podemos excluir alocados no construtor. o que fazer nessa ocasião.
7898 Chris_vr
5
  1. 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.

  2. Este fórum discute algumas maneiras de evitar vazamento de memória em C / C ++.

Benny Tjia
fonte
5

Pesquise ocorrências de seu código newe 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 ponteiros std::auto_ptr, ou boost::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.

Mankarse
fonte
nem sempre é possível apagar a memória alocada na constructor.How para lidar nesta situação
Chris_vr
@Chris_vr O que você quer dizer? Se todos os membros de seu ponteiro forem scope_ptrs, 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.
precisa saber é o seguinte
@ Chris_vr: se você tiver um exemplo específico, poste-o como uma nova pergunta, para que possamos discuti-lo lá.
Doc Brown
5

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

`$` valgrind ./your_CPP_program 
Divyanshu
fonte
5

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

#include <stdlib.h>

void * my_malloc(size_t n) {
    return malloc(n);
}

void leaky(size_t n, int do_leak) {
    void *p = my_malloc(n);
    if (!do_leak) {
        free(p);
    }
}

int main(void) {
    leaky(0x10, 0);
    leaky(0x10, 1);
    leaky(0x100, 0);
    leaky(0x100, 1);
    leaky(0x1000, 0);
    leaky(0x1000, 1);
}

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:

sudo apt-get install google-perftools
gcc -ggdb3 -o main.out main.c -ltcmalloc
PPROF_PATH=/usr/bin/google-pprof \
  HEAPCHECK=normal \
  HEAPPROFILE=ble \
  ./main.out \
;
google-pprof main.out ble.0001.heap --text

A saída da execução do programa contém a análise de vazamento de memória:

WARNING: Perftools heap leak checker is active -- Performance may suffer
Starting tracking the heap
Dumping heap profile to ble.0001.heap (Exiting, 4 kB in use)
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 272 bytes in 2 objects
The 2 largest leaks:
Using local file ./main.out.
Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start


If the preceding stack traces are not enough to find the leaks, try running THIS shell command:

pprof ./main.out "/tmp/main.out.24744._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv

If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more re
Exiting with error code (instead of crashing) because of whole-program memory leaks

e a saída de google-pprofcontém a análise de uso de heap:

Using local file main.out.
Using local file ble.0001.heap.
Total: 0.0 MB
     0.0 100.0% 100.0%      0.0 100.0% my_malloc
     0.0   0.0% 100.0%      0.0 100.0% __libc_start_main
     0.0   0.0% 100.0%      0.0 100.0% _start
     0.0   0.0% 100.0%      0.0 100.0% leaky
     0.0   0.0% 100.0%      0.0 100.0% main

A saída aponta para dois dos três vazamentos:

Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start

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:

gcc -fsanitize=address -ggdb3 -o main.out main.c
./main.out 

e saídas de execução:

=================================================================
==27223==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4096 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f210 in main /home/ciro/test/main.c:20
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 256 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1f2 in main /home/ciro/test/main.c:18
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1d4 in main /home/ciro/test/main.c:16
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

SUMMARY: AddressSanitizer: 4368 byte(s) leaked in 3 allocation(s).

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:

sudo apt-get install valgrind
gcc -ggdb3 -o main.out main.c
valgrind --leak-check=yes ./main.out

Resultado:

==32178== Memcheck, a memory error detector
==32178== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32178== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==32178== Command: ./main.out
==32178== 
==32178== 
==32178== HEAP SUMMARY:
==32178==     in use at exit: 4,368 bytes in 3 blocks
==32178==   total heap usage: 6 allocs, 3 frees, 8,736 bytes allocated
==32178== 
==32178== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091B4: main (main.c:16)
==32178== 
==32178== 256 bytes in 1 blocks are definitely lost in loss record 2 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091D2: main (main.c:18)
==32178== 
==32178== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091F0: main (main.c:20)
==32178== 
==32178== LEAK SUMMARY:
==32178==    definitely lost: 4,368 bytes in 3 blocks
==32178==    indirectly lost: 0 bytes in 0 blocks
==32178==      possibly lost: 0 bytes in 0 blocks
==32178==    still reachable: 0 bytes in 0 blocks
==32178==         suppressed: 0 bytes in 0 blocks
==32178== 
==32178== For counts of detected and suppressed errors, rerun with: -v
==32178== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

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.

Ciro Santilli adicionou uma nova foto
fonte
4

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 ++.

Quando você executa o programa no depurador do Visual Studio, o Visual Leak Detector gera um relatório de vazamento de memória no final da sua sessão de depuração. O relatório de vazamento inclui a pilha de chamadas completa, mostrando como os blocos de memória vazados foram alocados. Clique duas vezes em uma linha na pilha de chamadas para ir para esse arquivo e linha na janela do editor.

Se você tiver apenas despejos de memória, poderá usar o !heap -lcomando 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.

fresky
fonte
4

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:

  • histórico baseado em linha do tempo do uso de memória e blocos de memória ao vivo
  • filtragem de operação de memória poderosa com base em heap, tag de memória, intervalo de tempo etc.
  • SDK para instrumentação manual com código fonte completo
  • suporte contínuo à integração através do uso da linha de comando
  • árvore de pilha de chamadas e navegação no mapa da árvore
  • muito mais.

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.

mtosic
fonte
Essa deve ser a resposta aceita. É uma ótima ferramenta e pode lidar com os volumes de alocações / desalocações que outras pessoas não podem.
Serge Rogatch 18/06
3

No Windows, você pode usar o heap de depuração CRT .

Existe algum padrão ou procedimento que você deve seguir para garantir que não haja vazamento de memória no programa.

Sim, não use o gerenciamento manual de memória (se você ligar deleteou delete[]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).

Cat Plus Plus
fonte
3

Respondendo à segunda parte da sua pergunta,

Existe algum padrão ou procedimento que você deve seguir para garantir que não haja vazamento de memória no programa.

Sim existe. E essa é uma das principais diferenças entre C e C ++.

No C ++, você nunca deve chamar newou deleteno 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:

  • o construtor adquire o recurso (chamando newse o recurso é uma alocação de memroy)
  • o destruidor libera o recurso,
  • a cópia e a atribuição são impedidas (tornando o construtor de cópia e os operadores de atribuição privados) ou são implementadas para funcionar corretamente (por exemplo, clonando o recurso subjacente)

Essa classe é instanciada localmente, na pilha ou como membro da classe, e não chamando newe 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::vectorarquivo seja liberado quando o vetor for destruído. Então, novamente, não armazene um ponteiro no contêiner (o que exigiria que você chamasse newe delete), 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 alocados newe 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.

jalf
fonte
se o ponteiro inteligente possui uma classe e essa classe contém o ponteiro de várias outras classes. quando o smart dispara, isso significa que todo o ponteiro interno será excluído com segurança.
7898 Chris_vr
@ Chris: Supondo que o objeto apontado pelo ponteiro inteligente tenha um destruidor que faça a limpeza necessária ou o objeto contenha membros que tenham destruidores para executar a limpeza necessária. Em essência, enquanto todo objeto se cuidar (limpar depois de si mesmo quando for destruído), e enquanto todo objeto for armazenado por valor, não como um ponteiro, tudo o que precisa ser liberado será liberado.
jalf
3

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:

  • Use após livre (desreferência de ponteiro oscilante)
  • Estouro de buffer de pilha
  • Estouro do buffer da pilha
  • Estouro de buffer global
  • Use após o retorno
  • Erros na ordem de inicialização

Esta ferramenta é muito rápida. A desaceleração média do programa instrumentado é ~ 2x.

Principiante
fonte
Veja especialmente LeakSanitizer
Gabriel Devillers
0

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.

orbitcowboy
fonte
-1

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
-3

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.

s. Heller
fonte