【调试手段】linux下valgrind内存泄露检查
参考文章:http://blog.csdn.net/wzzfeitian/article/details/8567030
文库资料: valgrind工具检查内存错误
参考网址:http://blog.csdn.net/dndxhej/article/details/7855520
参考网址:http://blog.csdn.net/sunmenggmail/article/details/10543483
参考网址:http://blog.csdn.net/erlang_hell/article/details/51360149
valgrind是Linux平台一个多用途的代码审查和内存调试工具。它可以在valgrind自己的环境中运行你的程序,监控malloc/free,(new/delete for C++)等内存调用。如果你用了未初始化的内存,数组越界写入,或者忘了free一个指针,valgrind会检测到它们。由于这些都是一些日常最普通的问题,这篇文章就主要介绍如何用valgrind来发现这类简单的内存问题,虽然valgrind可以做的更多。
对windows使用者来说,如果你没有对linux机器的访问权限,或者你想开发windows程序,那么你可能对IBM的Purity软件更有兴趣,Purity在检测内存问题方面与valgrind功能类似,你可以自己去下载它。
获取Valgrind
如果你正在运行linux,而没有安装valgrind,那么你可以从Valgrind download page下载。
安装很简单,只需要解压就可以了。(XYZ在下面的例子中是版本号的意思)
bzip2 -d valgrind-XYZ.tar.bz2
tar -xf valgrind-XYZ.tar
上面的操作会创建一个目录,名字为valgrind-XYZ,切换到这个目录,运行下面的命令
./configure
make
make install
现在你已经安装了valgrind,让我们看下怎么使用它
使用Valgrind查找内存泄漏
内存泄漏是最难检测的bug之一,因为直到你用完了内存而有一个malloc失败,它不会表现出任何外在的问题。实际上,当我们使用C/C++这类没有垃圾回收机制的语言来工作的时候,几乎一半的时间会花费在正确处理free内存的问题上。如果你的程序运行足够长的时间并且运行到了那个代码分支,即使一个错误也是代价巨大的。
当你用valgrind运行你的代码的时候,你需要指定使用valgrind的什么工具;简单地运行一下valgrind你就会得到当前的列表。在这篇文章中,我们主要使用memcheck工具,memcheck工具可以保证我们正确的内存使用。不加其他参数,valgrind会打印出调用call和malloc的一个概括信息(注意18490是我系统上的process id;在不同的运行时,它是不同的)
% valgrind --tool=memcheck program_name
...
=18515== malloc/free: in use at exit: 0 bytes in 0 blocks.
==18515== malloc/free: 1 allocs, 1 frees, 10 bytes allocated.
==18515== For a detailed leak analysis, rerun with: --leak-check=yes
如果你有一处内存泄漏,那么alloc和free的数目就会不同(你不能用free去释放一块属于多个alloc的内存)。我们稍后会回来看这个概况,但是现在,注意一些errors被制止了,因为它们是来自标准库的,而不是来自你的代码。
如果alloc和free的数目不同,你需要用选项--leak-check来重新运行程序。这会向你展示所有的没有相匹配的free的malloc/new等调用。
为了说明,我用一个简单的程序,我编译成可执行文件"example1"
#include <stdlib.h>
int main()
{char *x = malloc(100); /* or, in C++, "char *x = new char[100] */return 0;
}
% valgrind --tool=memcheck --leak-check=yes example1
这会产生关于上面展示的程序的一些信息,生成一份列表,调用malloc但是没有相应的free。
==2116== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2116== at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==2116== by 0x804840F: main (in /home/cprogram/example1)
这并没有按照我们希望的那样告诉我们太多,尽管我们知道这个内存泄漏是发现在main中对malloc的调用,但是我们不知道行号。这个问题是因为我们编译的时候没有用gcc的-g选项,这个选项会添加调试符号。因此我们重新编译,得到下面更有用的信息。
==2330== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2330== at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==2330== by 0x804840F: main (example1.c:5)
现在我们知道确切的行号,在哪里这块泄漏的内存被分配。尽管想要跟踪下去到free的时候,还是个问题,但是至少我们知道从哪开始查起。并且,既然对每一处malloc或new的调用,你都有计划如何处理这块内存,知道内存在哪里泄漏会让你知道从哪里开始查找问题。
有时,选项--leak-check=yes不会向你展示所有的内存泄漏。要找到所有的不成对的对free和new的调用,你需要使用选项--show-reachable=yes。它的输出基本是相同的,但是它会向你展示更多unfreed的内存。
使用Valgrind发现非法指针使用
Valgrind通过memcheck工具发现非法堆内存的使用。例如,如果你用malloc或new分配一个数组,然后尝试访问数组的边界外位置:
char *x = malloc(10);
x[10] = 'a';
Valgrind会检测到。例如,用valgrind运行下面的程序example2
#include <stdlib.h>int main()
{char *x = malloc(10);x[10] = 'a';return 0;
}
运行方法:
valgrind --tool=memcheck --leak-check=yes example2
结果为:
==9814== Invalid write of size 1
==9814== at 0x804841E: main (example2.c:6)
==9814== Address 0x1BA3607A is 0 bytes after a block of size 10 alloc'd
==9814== at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==9814== by 0x804840F: main (example2.c:5)
上面的结果告诉我们:我们正在越界使用一个被分配了10bytes空间的指针,结果有一个‘Invalid write’。如果我们尝试从那块内存读数据,我们会被将被警告'Invalid read of size X',此处的X是我们尝试读取的内存大小(对char类型来说,它是1,对int就是2或者4).通常,Valgrind会打印出函数调用的堆栈信息,我们就会确切地知道错误在哪发生。
使用Valgrind检测未初始化的变量使用
Valgrind还有一个用途,它可以检测到在条件语句中使用未初始化的值。尽管你应该习惯在创建一个变量的时候进行初始化,但是Valgrind会帮助你发现那些你忘记的地方。例如,运行下面example3的代码:
#include <stdio.h>int main()
{int x;if(x == 0){printf("X is zero"); /* replace with cout and include iostream for C++ */}return 0;
}
结果为:
==17943== Conditional jump or move depends on uninitialised value(s)
==17943== at 0x804840A: main (example3.c:6)
Valgrind会足够聪明,知道一个变量是否被用一个未初始化的变量赋值,例如,下面的代码:
#include <stdio.h>int foo(int x)
{if(x < 10){printf("x is less than 10\n");}
}int main()
{int y;foo(y);
}
结果如下:
==4827== Conditional jump or move depends on uninitialised value(s)
==4827== at 0x8048366: foo (example4.c:5)
==4827== by 0x8048394: main (example4.c:14)
你可能会认为问题出在foo函数中,堆栈信息也不重要。但是,由于main传了一个未初始化的值给foo函数(你从来没有给y赋值),那么我们查找问题并跟踪变量的赋值堆栈,直到我们发现了一个未初始化的变量。
这只会在你的程序走到那个分支的时候帮助你,尤其是条件语句。所以确保在测试的时候能够让程序走过所有的分支。
Valgrind能够发现的其他问题
Valgrind会检测到其他的一些不恰当的内存使用:如果你free一个指针两次,Valgrind会为你检测到;你会得到下面错误:
Invalid free()
并跟随一些相关的堆栈
Valgrind也会检测到释放内存时选择了错误的方法。例如,在C++中,有3中基本的释放动态内存的方法:free,delete,delete[]。free函数只跟malloc匹配,delete只跟new匹配,delete[]只跟new[]匹配。(尽管有些编译器会为你处理此类用错delete的情况,但是不能保证所有的编译器都能,它不是变准要求的)。
如果你触发了这类问题,你会得到错误:
Mismatched free() / delete / delete []
这是必须要修复的,即使你的程序碰巧可以工作。
Valgrind不能发现的东西
Valgrind不能检查静态数组的边界(在栈上分配的空间)。因此,如果你在你的函数中声明一个数组
int main()
{char x[10];x[11] = 'a';
}
那么,Valgrind不会警告你的!一个可能用于测试目的的解决方案是在你需要做边界检测的地方转换你的静态数组为从堆上动态分配内存,但是这会产生很多unfreed的内存。
其他更过的警告信息
Valgrind的缺点是什么呢?它会消耗更多的内存--最大两倍于你源程序需要的内存。如果你在检测一个很大的内存问题,那这可能会导致一些问题。它会需要更长的时间去运行你的程序。这通常不应该有什么问题,并且也只是在你测试的时候有影响而已。但是如果你正在运行一个本来已经很慢的程序,那么这也可能会是个问题。
总结
Valgrind是一个对x86和AMD64结构的一个工具,运行在Linux环境下。它允许程序员在它的环境下运行程序,因此可以检测不成对的malloc和其他使用非法内存(例如未初始化的内存)的问题或者非法内存操作(例如重复free同一块内存,调用错误的析构函数)。Valgrind不能检测静态内存问题。
【调试手段】linux下valgrind内存泄露检查相关推荐
- 【调试】Linux下超强内存检测工具Valgrind
[调试]Linux下超强内存检测工具Valgrind 内容简介 Valgrind是什么? Valgrind的使用 Valgrind详细教程 1. Valgrind是什么? Valgrind是一套Lin ...
- Linux下查看内存泄露的命令
一. Linux下确定内存泄露 在做嵌入式开发中,例如,在 Linux 下做 C/C++ 开发,会因为调用 malloc/calloc() 函数,忘记释放堆内存.程序运行久了,会发生内存泄露问题 ...
- Valgrind 检测linux上c++内存泄露
Linux c++上常用内存泄露检测工具有valgrind, Rational purify.Valgrind免费.Valgrind 可以在 32 位或 64 位 PowerPC/Linux 内核上工 ...
- Valgrind 检测linux上c++内存泄露(转)
Linux c++上常用内存泄露检测工具有valgrind, Rational purify.Valgrind免费.Valgrind 可以在 32 位或 64 位 PowerPC/Linux 内核上工 ...
- VC内存泄露检查工具:VisualLeakDetector
From: http://www.xdowns.com/article/170/Article_3060.html 初识Visual Leak Detector 灵活自由是C/C++语言 ...
- linux跟踪内存检测原理,wooyun/Linux下基于内存分析的Rootkit检测方法.html at master · exitmsconfig/wooyun · GitHub...
Linux下基于内存分析的Rootkit检测方法 - 路人甲 原文地址:http://drops.wooyun.org/tips/4731 0x00 引言 某Linux服务器发现异常现象如下图,确定被 ...
- C++ 实现内存泄露检查
内存泄漏一直是 C++ 中比较令人头大的问题, 即便是很有经验的 C++程序员有时候也难免因为疏忽而写出导致内存泄漏的代码.除了基本的申请过的内存未释放外,还存在诸如异常分支导致的内存泄漏等等.本项目 ...
- Android C++ Native 内存泄露检查工具Raphael使用介绍
Android C++ Native 内存泄露检查工具使用介绍 实现原理 使用方法 Raphael添加到测试apk 添加项目依赖 同步gradle 启动泄露检测功能 直接使用boardcast功能控制 ...
- linux单步调试方法,linux下gdb单步调试(中).doc
linux下gdb单步调试(中) linux下gdb单步调试(中) linux下gdb单步调试(中) 一.设置断点( BreakPoint ) 我们用 break 命令来设置断点.正面有几点设置断点的 ...
最新文章
- Hadoop生态圈-Flume的组件之自定义拦截器(interceptor)
- scrum敏捷开发工具实践分享
- Java Spring MVC框架搭建(一)
- abaqus实例详解_Abaqus接触分类、形成和定义
- 未来教育计算机二级书怎么样,未来教育计算机二级
- 第十五篇 Python之文件处理
- el表达式/jstl保留两位小数
- Oracle书籍资料链接——更新ing
- head first设计模式之设计原则
- 网店宝贝复制专家操作手册
- 神州数码交换机的数据备份
- flash动画入门篇
- 数据分析(2)——假设检验的详细原理步骤
- php 获取支付宝账号密码,php支付宝单笔转账到支付宝账户,用户提现业务-Go语言中文社区...
- grpc服务认证实现方式
- 用Python自动生成数据日报!
- 实验四 微程序控制器实验
- 计算机用户名如何修改,如何修改电脑用户名
- 校招----shein一面面经
- Java--对象的比较2(类比)
热门文章
- 客户和顾客是一个意思吗_履约保证金和投标保证金是一个意思吗?
- Excel中的fixed函数
- 使用Dwr时出现java.lang.SecurityException: Access to debug pages is denied
- 服务器返回的数据把标签转义为其它字符
- linux上oracle导入mysql_linux下的oracle数据库和表空间的导入导出
- 【电脑帮助】解决Wind10系统照片中自带的保存的图片和本机照片的问题
- java response文件流下载,后缀名称设置
- jasperreport linux 中文不能显示的解决方法
- nginx中root和alias的区别
- 连接Oracle时报错ORA-28547