如何在Linux下检测程序是否存在内存泄漏?

C语言是嵌入式开发中永远回避不了的语言,不管是操作系统还是裸机开发,无处不体现着C语言的高效。 C语言可以直接操作内存,有着完善的内存管理机制,用好了可以削铁如泥,用不好自断一臂!

不管是C还是C++,很多同学都不可避免犯内存泄漏的错误。因为我们平时写的都是些小程序,就算申请的内存没有释放,也不会影响程序结果,所以很少会关注内存泄漏的问题。但是如果把这个问题放在商用的项目中,就会是一个不小的隐患。

如何判断程序中是否存在内存泄漏,今天就来跟大家分享一个常用工具-- valgrind

valgrind 堪称Linux内存调试神器,可以用它检测内存泄漏、野指针,或者检查函数调用、缓存、堆栈使用问题。先看下 valgrind 的man手册:

SYNOPSIS
       valgrind [valgrind-options] [your-program] [your-program-options]
TOOL SELECTION OPTIONS
       The single most important option.

       --tool=<toolname> [default: memcheck]
           Run the Valgrind tool called toolname, e.g. memcheck, cachegrind, callgrind, helgrind, drd, massif,
           lackey, none, exp-sgcheck, exp-bbv, exp-dhat, etc.

它的主要功能都放在【–tool=】选项。

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

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

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

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

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

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

未初始化的指针

test1.c

#include <stdio.h>

int main()  
{
    int *p;

    printf("%d\n", *p);

    return 0;  
}

编译的时候最好加上【-g】选项,【-g】选项可以在调试的时候看到行号。

通过 valgrind 调试程序。

在这里插入图片描述
调试信息清楚的告诉我们,程序第7行存在问题:1、使用了未初始化的指针;2、非法访问指针。导致程序最后出现段错误。

内存泄漏

test2.c

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

int main()
{
    int *p = (int *)malloc(sizeof(int) * 10);

    memset(p, 0, 10);

    return 0; 
}

运行结果:

在这里插入图片描述

加上【–leak-check=full】再次运行:

在这里插入图片描述这次运行,明确指出了程序第7行存在内存泄漏,申请了内存,但是最后并没有释放掉。

使用野指针

test3.c

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

int main() 
{
    int *p = (int *)malloc(sizeof(int) * 10);

    memset(p, 0, sizeof(int));

    free(p);

    printf("%d\n", p[0]);

    return 0;  
}

运行结果:

在这里插入图片描述
程序中虽然使用了野指针,但是运行并没有出现段错误。这就是C语言内存管理不严格的地方, 只有访问了系统保护的内存,才会出现段错误,虽然内存被释放了,但并没有被保护,所以就算访问,也不会出现问题。 但是这种不合法的使用还是能被valgrind检测出来。

堆栈越界访问

test4.c

#include <stdio.h> 
#include <stdlib.h>

int main()
{
    char *p = (char *)malloc(sizeof(char) * 16);

    p[20] = 'x';

    free(p);

    return 0; 
}

运行结果:

在这里插入图片描述

重复释放内存

test5.c

#include <stdio.h> 
#include <stdlib.h>

int main()
{
    char *p = (char *)malloc(sizeof(char) * 1024);

    free(p); 
    free(p);

    return 0; 
}

运行结果:

在这里插入图片描述

new和delete

valgrind 同样适用于C++程序,比如new和delete没有匹配使用、堆栈内存越界访问,用法和上面的一样,这里就不写代码了。

总结

内存泄漏问题在定位问题的时候很难被发现,所以这个时候valgrind就可以发挥很大的力量。 同时也要提醒大家,平时写代码的时候也要注意,申请了内存用完后一定要释放,就像去图书馆借书一样,光借不还,图书馆迟早要关门。 养成良好的编码习惯,毕竟调试程序也很废脑子。

更多文章、视频、嵌入式学习资源,微信关注 【学益得智能硬件】
在这里插入图片描述

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页