Linux - ferramenta Valgrind detecção de vazamento de memória e análise de desempenho

Prefácio

O vazamento de memória é um problema que costumamos encontrar ao depurar programas, e existem muitos softwares de análise de vazamento de memória. Este artigo analisa principalmente o uso de ferramentas Valgrind.

Introdução e instalação do Valgrind

Baixe do site oficial da Valgrind: http://valgrind.org/downloads/current.html#current
A última versão é valgrind 3.15.0, e o download no site oficial é muito lento. A ferramenta pode ser instalada diretamente da fonte do espelho. do seguinte modo:

sudo apt install valgrind

Insira a descrição da imagem aqui
Use o comando valgrind para verificar se a instalação foi bem-sucedida.

valgrind ls -l

Insira a descrição da imagem aqui

Uso de Valgrind

O kit de ferramentas Valgrind contém várias ferramentas, como Memcheck, Cachegrind, Helgrind, Callgrind, Massif.

Memcheck

A ferramenta mais comumente usada é usada para detectar problemas de memória no programa. Todas as leituras e gravações na memória serão detectadas e todas as chamadas para malloc () / free () / new / delete serão capturadas. Portanto, a ferramenta Memcheck verifica principalmente os seguintes erros de programa.
(1) Uso de memória não inicializada
(2) Uso de memória liberada Leitura / gravação de memória após ela ter sido liberada
(3) Uso de mais espaço de memória alocado de malloc Leitura / gravação no final de malloc 'd blocks
(4) Acesso ilegal à pilha Lendo / gravando áreas inadequadas na pilha
(5) Se o espaço solicitado é liberado Vazamentos de memória - onde ponteiros para blocos malloc são perdidos para sempre
(6) malloc / free / new / Uso incompatível de malloc / new / new [] vs free / delete / delete []
(7) Ponteiros src e dst sobrepostos em memcpy () e funções relacionadas.
Esses problemas são freqüentemente C O problema mais problemático dos programadores de / C ++, Memcheck está aqui para ajudar.

Callgrind

Uma ferramenta de análise semelhante ao gprof, mas sua observação do funcionamento do programa é mais sutil e pode nos fornecer mais informações. Ao contrário do gprof, ele não requer opções especiais adicionais ao compilar o código-fonte, mas é recomendado adicionar opções de depuração. Callgrind coleta alguns dados quando o programa está em execução, constrói um gráfico de relacionamento de chamada de função e, opcionalmente, executa a simulação de cache. No final da execução, ele gravará os dados da análise em um arquivo. callgrind_annotate pode converter o conteúdo deste arquivo em um formato legível.

Cachegrind

O Cache Analyzer, que simula o cache de primeiro nível I1, Dl e o cache de segundo nível na CPU, pode apontar com precisão as falhas e acertos do cache no programa. Se necessário, ele também pode nos fornecer o número de falhas de cache, o número de referências de memória e o número de instruções geradas por cada linha de código, cada função, cada módulo e todo o programa. Isso é uma grande ajuda para otimizar o programa.

Helgrind

É usado principalmente para verificar problemas de competição em programas multithread. Helgrind procura por áreas na memória que são acessadas por vários threads e não estão travadas de forma consistente.Essas áreas são geralmente lugares onde os threads perdem a sincronização e podem levar a erros que são difíceis de descobrir. Helgrind implementou um algoritmo de detecção de competição chamado "Eraser" e fez mais melhorias para reduzir o número de erros relatados. No entanto, Helgrind ainda está em fase experimental.

Maciço

Analisador de pilha, pode medir quanta memória o programa usa na pilha, nos diz o bloco de heap, o bloco de gerenciamento de heap e o tamanho da pilha. O Massif pode nos ajudar a reduzir o uso de memória.Em sistemas modernos com memória virtual, ele também pode acelerar a execução de nossos programas e reduzir a chance de os programas permanecerem na área de swap.

Uso: valgrind [opções] prog-and-args
[opções]: opções comuns, aplicáveis ​​a todas as ferramentas Valgrind

-tool=<name> 最常用的选项。运行 valgrind中名为toolname的工具。默认memcheck。

    memcheck ------> 这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。

    callgrind ------> 它主要用来检查程序中函数调用过程中出现的问题。

    cachegrind ------> 它主要用来检查程序中缓存使用出现的问题。

    helgrind ------> 它主要用来检查多线程程序中出现的竞争问题。

    massif ------> 它主要用来检查程序中堆栈使用中出现的问题。

    extension ------> 可以利用core提供的功能,自己编写特定的内存调试工具

-h –help 显示帮助信息。
-version 显示valgrind内核的版本,每个工具都有各自的版本。
-q –quiet 安静地运行,只打印错误信息。
-v –verbose 更详细的信息, 增加错误数统计。
-trace-children=no|yes 跟踪子线程? [no]
-track-fds=no|yes 跟踪打开的文件描述?[no]
-time-stamp=no|yes 增加时间戳到LOG信息? [no]
-log-fd=<number> 输出LOG到描述符文件 [2=stderr]
-log-file=<file> 将输出的信息写入到filename.PID的文件里,PID是运行程序的进行ID
-log-file-exactly=<file> 输出LOG信息到 file
-log-file-qualifier=<VAR> 取得环境变量的值来做为输出信息的文件名。 [none]
-log-socket=ipaddr:port 输出LOG到socket ,ipaddr:port

Teste de exemplo

Escreva um exemplo:

#include <stdlib.h>
#include <malloc.h>
#include <string.h>

void test()
{
        int *ptr = malloc( sizeof(int)* 10);
        ptr[10] =100;// 内存越界 

        memcpy(ptr+1,ptr,5); 踩内存,内存的源地址和目的地址重叠

        free(ptr);
        free(ptr);// 重复释放

        int *p1;
        *p1 =10;// 非法指针 


}

int main(int argc,char** argv)
{
        test();
        return 0;
}
gcc -g  -o test -fno-inline   test.c 

-G -fno-inline é uma opção de compilação para reter informações de depuração, caso contrário, o seguinte valgrind não pode exibir o número da linha de erro e ser executado diretamente.
Execute diretamente ./test
Insira a descrição da imagem aqui
prompt; double free ou corrompido, relatar erro de despejo de núcleo.
Use a ferramenta valgrind abaixo para analisar.

valgrind --tool=memcheck --leak-check=full --show-reachable=yes --trace-children=yes ./test

--Leak-check = full refere-se a verificar vazamentos de memória completamente,

--Show-reachable = yes é para mostrar a localização do vazamento de memória,

-Trace-children = yes é seguir o processo filho.
resultado da operação:

root@ubuntu:~# valgrind --tool=memcheck --leak-check=full --show-reachable=yes --trace-children=yes ./test
==43170== Memcheck, a memory error detector
==43170== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==43170== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==43170== Command: ./test
==43170== 
==43170== Invalid write of size 4  // 无效写入,内存越界了 
==43170==    at 0x4005F4: test (test.c:8)
==43170==    by 0x400653: main (test.c:23)
==43170==  Address 0x5204068 is 0 bytes after a block of size 40 alloc'd
==43170==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==43170==    by 0x4005E7: test (test.c:7)
==43170==    by 0x400653: main (test.c:23)
==43170== 
==43170== Source and destination overlap in memcpy(0x5204044, 0x5204040, 5)// 内存地址重叠
==43170==    at 0x4C32513: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==43170==    by 0x400615: test (test.c:10)
==43170==    by 0x400653: main (test.c:23)
==43170== 
==43170== Invalid free() / delete / delete[] / realloc()// 重复释放 
==43170==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==43170==    by 0x40062D: test (test.c:13)
==43170==    by 0x400653: main (test.c:23)
==43170==  Address 0x5204040 is 0 bytes inside a block of size 40 free'd
==43170==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==43170==    by 0x400621: test (test.c:12)
==43170==    by 0x400653: main (test.c:23)
==43170==  Block was alloc'd at
==43170==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==43170==    by 0x4005E7: test (test.c:7)
==43170==    by 0x400653: main (test.c:23)
==43170== 
==43170== Use of uninitialised value of size 8 // 使用了未初始化的指针,非法的指针 
==43170==    at 0x400632: test (test.c:16)
==43170==    by 0x400653: main (test.c:23)
==43170== 
==43170== Invalid write of size 4
==43170==    at 0x400632: test (test.c:16)
==43170==    by 0x400653: main (test.c:23)
==43170==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==43170== 
==43170== 
==43170== Process terminating with default action of signal 11 (SIGSEGV)//由于非法指针赋值导致的程序崩溃
==43170==  Access not within mapped region at address 0x0
==43170==    at 0x400632: test (test.c:16)
==43170==    by 0x400653: main (test.c:23)
==43170==  If you believe this happened as a result of a stack
==43170==  overflow in your program's main thread (unlikely but
==43170==  possible), you can try to increase the size of the
==43170==  main thread stack using the --main-stacksize= flag.
==43170==  The main thread stack size used in this run was 8388608.
==43170== 
==43170== HEAP SUMMARY:
==43170==     in use at exit: 0 bytes in 0 blocks
==43170==   total heap usage: 1 allocs, 2 frees, 40 bytes allocated
==43170== 
==43170== All heap blocks were freed -- no leaks are possible
==43170== 
==43170== For counts of detected and suppressed errors, rerun with: -v
==43170== Use --track-origins=yes to see where uninitialised values come from
==43170== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0) //一共5个错误
Segmentation fault (core dumped)

O Callgrind usa:
uma ferramenta de análise semelhante ao gprof, mas que observa o funcionamento do programa com mais nuances e pode nos fornecer mais informações. Ao contrário do gprof, ele não requer opções especiais adicionais ao compilar o código-fonte, mas é recomendado adicionar opções de depuração. Callgrind coleta alguns dados quando o programa está em execução, constrói um gráfico de relacionamento de chamada de função e, opcionalmente, executa a simulação de cache. No final da execução, ele gravará os dados da análise em um arquivo. callgrind_annotate pode converter o conteúdo deste arquivo em um formato legível.

Exemplos de uso de cachegrind:

#include <stdio.h>
#include <malloc.h>
void test()
{
    sleep(1);
}
void f()
{
    int i;
    for( i = 0; i < 5; i ++)
        test();
}
int main()
{
    f();
    printf("process is over!\n");
    return 0;
}

O método de uso é: valgrind --tool = cachegrind ./test
Insira a descrição da imagem aqui

Helgrind
é usado principalmente para verificar problemas de competição em programas multithread. Helgrind procura por áreas na memória que são acessadas por vários threads e não estão travadas de forma consistente.Essas áreas são geralmente lugares onde os threads perdem a sincronização e podem levar a erros que são difíceis de descobrir. Helgrind implementou um algoritmo de detecção de competição chamado "Eraser" e fez mais melhorias para reduzir o número de erros relatados. No entanto, Helgrind ainda está em fase experimental.

Vamos primeiro dar um exemplo de competição:

#include <stdio.h>
#include <pthread.h>
#define NLOOP 50
int counter = 0; / * incrementado por threads * /
void * threadfn (void *);

int main (int argc, char ** argv)
{ pthread_t tid1, tid2, tid3;

pthread_create(&tid1, NULL, &threadfn, NULL);  
pthread_create(&tid2, NULL, &threadfn, NULL);  
pthread_create(&tid3, NULL, &threadfn, NULL);  


/* wait for both threads to terminate */  
pthread_join(tid1, NULL);  
pthread_join(tid2, NULL);  
pthread_join(tid3, NULL);  


return 0;  

}

void threadfn (void vptr)
{ int i, val; for (i = 0; i <NLOOP; i ++) { val = counter; printf ("% x:% d \ n", (unsigned int) pthread_self (), val +1); counter = val + 1; } return NULL; } A condição de corrida deste programa está nas linhas 30 ~ 32. O efeito que queremos é que os três threads acumulem a variável global 50 vezes, e o valor final da variável global é 150. Como não há bloqueio aqui, é óbvio que a condição de corrida impede o programa de atingir nosso objetivo. Vamos ver como Helgrind pode nos ajudar a detectar as condições de corrida. Primeiro compile o programa: gcc -o test thread.c -lpthread, depois execute: valgrind --tool = helgrind ./test A saída é a seguinte: 49c0b70: 1 49c0b70: 2











4666 Tópico # 3 foi criado
4666 em 0x412E9D8: clone (clone.S: 111)
4666 por 0x40494B5: pthread_create @@ GLIBC_2.1 (createthread.c: 256)
4666 por 0x4026E2D: pthread_create_WRK (hg_intercepts.c: 257)
4666por 0x4026F8B: pthread_create @
(hg_intercepts.c: 288)
4666 por 0x8048524: main (em /home/yanghao/Desktop/testC/testmem/a.out)
4666
4666 O tópico 2 foi criado
4666 em 0x412E9D8: clone (clone.S: 111)
4666 por 0x40494B5: pthread_create @@ GLIBC_2.1 (createthread.c: 256)
4666 por 0x4026E2D: pthread_create_WRK (hg_intercepts.c: 257)
4666por 0x4026F8B: pthread_create @
(hg_intercepts.c: 288)
4666 por 0x8048500: main (em /home/yanghao/Desktop/testC/testmem/a.out)
4666
4666 Possível corrida de dados durante a leitura do tamanho 4 em 0x804a028 pelo thread # 3
4666 em 0x804859C: threadfn (em /home/yanghao/Desktop/testC/testmem/a.out)

4666 por 0x4026F60: mythread_wrapper (hg_intercepts.c: 221)
4666 por 0x4048E98: start_thread (pthread_create.c: 304)
4666 por 0x412E9ED: clone (clone.S: 130)
4666 Isso está em conflito com uma gravação anterior de tamanho 4 pela discussão # 2
4666 em 0x80485CA: threadfn (em /home/yanghao/Desktop/testC/testmem/a.out)
4666 por 0x4026F60: mythread_wrapper (hg_intercepts.c: 221)
4666 por 0x4048E98: start_thread (pthread_create.c: 304)
4666 por 0x412E9ED: clone (clone.S: 130)
4666
4666 Possível corrida de dados durante a gravação de tamanho 4 em 0x804a028 pelo thread # 2
4666 em 0x80485CA: threadfn (em /home/yanghao/Desktop/testC/testmem/a.out)
4666 por 0x4026F60: mythread_wrapper (hg_intercepts.c: 221)
4666 por 0x4048E98: start_thread (pthread_create.c: 304)
4666 por 0x412E9ED: clone (clone.S: 130)
4666 Isso está em conflito com uma leitura anterior de tamanho 4 pela discussão # 3
4666 em 0x804859C: threadfn (em /home/yanghao/Desktop/testC/testmem/a.out)
4666 por 0x4026F60: mythread_wrapper (hg_intercepts.c: 221)
4666 por 0x4048E98: start_thread (pthread_create.c: 304)
4666 por 0x412E9ED: clone (clone.S: 130)
4666
49c0b70: 3

55c1b70: 51
4666
4666 Para contagens de erros detectados e suprimidos, execute novamente com: -v
4666 Use --history-level = aprox. Ou = nenhum para aumentar a velocidade, em
4666 o custo da precisão reduzida de informações de acesso conflitante
4666 RESUMO DE ERROS: 8 erros de 2 contextos (suprimido: 99 de 31)

Helgrind encontrou com sucesso a posição da competição, mostrada em negrito.

Maciço

Analisador de pilha, pode medir quanta memória o programa usa na pilha, nos diz o bloco de heap, o bloco de gerenciamento de heap e o tamanho da pilha. O Massif pode nos ajudar a reduzir o uso de memória.Em sistemas modernos com memória virtual, ele também pode acelerar a execução de nossos programas e reduzir a chance de os programas permanecerem na área de swap.

Massif perfis a alocação e liberação de memória. Os desenvolvedores de programas podem usá-lo para compreender profundamente o comportamento de uso de memória do programa e otimizar o uso de memória. Este recurso é especialmente útil para C ++, porque C ++ tem muitas liberações e alocações de memória ocultas.

Além disso, lacaio e nulgrind também fornecerão. Lackey é uma ferramenta pequena que raramente é usada; Nulgrind apenas mostra aos desenvolvedores como criar uma ferramenta. Não vamos apresentá-lo.

Princípio de detecção de memória

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui

Citado em: https://www.cnblogs.com/AndyStudy/p/6409287.html
https://www.linuxidc.com/Linux/2012-06/63754.htm

Acho que você gosta

Origin blog.csdn.net/u014470361/article/details/98384767
Recomendado
Clasificación