C语言内存泄露检测Valgrind

valgrind使用场景

检查代码中在堆上分配存储器,但是没释放的位置,也就是找出存储器泄露位置

valgrind工作原理

通过伪造malloc可以监控分配在堆上的数据,当程序想分配堆存储器时,valgrind将会拦截你对malloc和free的调用,然后运行自己的malloc和free函数,它会记录哪段代码分配了哪段存储器,结束的时候,valgrind会汇报堆上有哪些数据,并告诉你这些数据由哪段代码创建

安装valgrind

curl -O http://valgrind.org/downloads/valgrind-3.11.0.tar.bz2
tar -xjvf valgrind-3.11.0.tar.bz2
cd valgrind-3.11.0
./configure && make && make install
valgrind --version

使用valgrind

gcc -g test.c -o test (其中-g是告诉编译器要记录需编译代码的行号)
valgrind --leak-check=full ./test

例子

createByMalloc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//结构定义函数体的外面多个函数才能共享
typedef struct island {
    char *name;
    char *open;
    char *close;
    struct island *next;
} island;


void display(island *start);
island* create(char *name);

int main()
{
    char name[80];
    fgets(name, 80, stdin);
    island *i = create(name);

    fgets(name, 80, stdin);
    island *i1 = create(name);
    i->next = i1;
    display(i);
    release(i);
}

island* create (char *name)
{
    island *i = malloc(sizeof(island));
    //注意在此处一定用用strdup在堆上存储,如果都是在栈上存储,函数结束后会释放内存空间,每次都只能保存最后传入的name指针指向的值
    i->name = strdup(name);
    i->open = "09:00";
    i->close = "17:00";
    i->next = NULL;

    return i;
}


void display(island *start) {
    island *i = start;
    for (;i!=NULL;i=i->next) {
        printf("name:%s,open:%s-%s\n",i->name, i->open, i->close);
    }
}

gcc -g createByMalloc.c -o createByMalloc
valgrind --leak-check=full ./createByMalloc

Alt text

1.total heap usage: 520 allocs, 100 frees, 49,567 bytes allocated
    表示520次存储器,100次被释放

2.at 0x100007EA1: malloc (vg_replace_malloc.c:303)
  by 0x100000D7A: create (createByMalloc.c:33)
  by 0x100000CED: main (createByMalloc.c:23)
    明确指出了可能出问题的行,查看代码可以发现是create的33行分配的堆上的存储器没有被释放,所以加上释放代码就好了

正确例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//结构定义函数体的外面多个函数才能共享
typedef struct island {
    char *name;
    char *open;
    char *close;
    struct island *next;
} island;


void display(island *start);
void release1(island *start);
void release(island *start);
island* create(char *name);

int main()
{
    char name[80];
    fgets(name, 80, stdin);
    island *i = create(name);

    fgets(name, 80, stdin);
    island *i1 = create(name);
    i->next = i1;
    display(i);
}

island* create (char *name)
{
    island *i = malloc(sizeof(island));
    //注意在此处一定用用strdup在堆上存储,如果都是在栈上存储,函数结束后会释放内存空间,每次都只能保存最后传入的name指针指向的值
    i->name = strdup(name);
    i->open = "09:00";
    i->close = "17:00";
    i->next = NULL;

    return i;
}


void display(island *start) {
    island *i = start;
    for (;i!=NULL;i=i->next) {
        printf("name:%s,open:%s-%s\n",i->name, i->open, i->close);
    }
}

void release1(island *start) {
    island *i = NULL;
    for(i=start;i!=NULL;i=i->next) {
        free(i->name);
        free(i);
    }
}

void release(island *start) {
    island *i = start;
    island *next = NULL;
    for(;i!=NULL;i=next) {
        next = i->next;
        free(i->name);
        free(i);
    }
}
坚持原创技术分享,您的支持将鼓励我继续创作!