C++内存错误检测工具

来源:互联网 发布:数据对接子系统 编辑:程序博客网 时间:2024/06/06 23:56

C++内存错误检测工具


简介
1)开发时,该如何尽力避免内存错误的发生;
2)开发后,该如何去确定真的没有问题;


相关内容
1)内存使用方式简介;
2)使用智能指针降低内存泄露的风险;
3)windows上,使用Visual Studio做内存错误检测;
4)Linux上,使用Valgrind做内存错误检测;


问题引出
昨天遇到了一个大牛,学到了不少东西。其中一些东西就是关于内存泄露的。对话大概是这样的。
大牛:”你怎么保证自己的代码没有内存泄露。”
我:”!@#$%^&*!(大概说的是,只要注意一点,不会出现的)”
大牛:”呵呵,你用什么证明。”


一、内存使用方式简介
1、代码段:只读数据;

2、数据段/BSS段:如果没有显式初始化,会被初始化为零;

3、栈空间数据:
一般指局部变量。这类变量若未初始化,则会被赋予随机的初值。
如果在栈中申请过大的局部变量,会出现栈溢出。

4、堆空间数据:
出现内存错误的情况可以有两种:
1)申请了一块内存,但未释放,俗称内存泄露;
2)对于同一块内存,释放了多次;

5、其它
1)野指针:一般指未初始化或已释放的指针。若去访问这个指针,将出错;
2)越界访问:通常在使用数组时被强调;
3)只读的数据和资源:如果去写了,也就错了;
4)访问超出控制范围的内存:比如先保存一个局部变量的地址,超出它的作用域之后,又去访问这个地址;


二、使用智能指针降低内存泄露的风险
有人说,”如果可以,尽量使用智能指针。”也有人说,”如果项目的大多数代码都用的指针,那就别用智能指针,不然显得乱。”


在可以使用智能指针的场景中,智能指针需要尽可能的替代指针的存在。

以shared_ptr<Type>为例,Type * ptr  =>  shared_ptr<Type> ptrnew Type()  =>  make_shared<Type>()delete ptr  =>  智能指针会自动释放


三、windows上,使用Visual Studio做内存错误检测
当一个观点无法被直接证明的时候,我们可以采用旁证,即借助大家都相信的东西来间接证明。在内存错误方面,我们可以使用第三方工具来进行检测。


在windows上,Visual Studio是最常用的开发工具,也可以用来检测内存错误。它提供的功能有很多,都可以在crtdbg.h文件中找到。


最简单直接的一种使用方式,是将内存泄露的代码位置打印出来。
具体方法,就是在代码前加几行代码,像这样:

#include <crtdbg.h>#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)static int tmp = _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );


假设测试代码如下:

#ifdef _MSC_VER#ifdef _DEBUG#include <crtdbg.h>#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)static int tmp = _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);#endif#endifint main(){    char * ptr = new char;      return 0;}


以debug模式编译运行后,在输出窗口可以看到:

Detected memory leaks!Dumping objects ->xxx\main.cpp(14) : {75} normal block at 0x0102AFD8, 1 bytes long. Data: < > CD Object dump complete.


或者可以用另一种写法,在这里可以看到。大体上是一样的,只是做了一些处理,方便使用。


四、Linux上,使用Valgrind做内存错误检测
如果不使用第三方工具,g++本身其实也可以做很多内存错误方面的检测工作。只需要在编译时,加入-Wall选项,它就会尽可能的打印出警告信息。这其中就包含了很多内存错误的警告。

再回到使用第三方工具的话题。在Linux上,可以使用Valgrind做内存错误检测。老样子,先从简单的用法开始。可以像这样:

sudo apt-get install valgrindvalgrind --tool=memcheck --show-reachable=yes --read-var-info=yes \--verbose --time-stamp=yes --leak-check=full --log-file=logfile.log <debug编译的可执行文件>


执行过后,我们可以再logfile.log里查看内存错误检测结果。查阅时,可以先搜索关键字ERROR。这样可以很快的定位到相关信息,包括错误代码位置,错误原因等。


上面的命令包含三个部分,即valgrind,一系列选项,可执行文件。首先需要注意的是,这个可执行文件是debug模式编译的。如:

g++ -o test test.cpp -Wall -g


然后是这些选项,这里给出的并不全,但可用。

1. --tool=<toolname> [default: memcheck]    valgrind是一套工具的集合,memcheck是较为常用的一个,作为默认选择;2. --show-reachable=yes    对于控制范围之外的内存泄漏也进行检测,如全局指针、static指针等;3. --read-var-info=yes    应用程序会变慢,但是能给出更多的错误细节;4. --verbose    打印更详细的信息;5. --time-stamp=yes    顾名思义,显示时间戳;6. --leak-check=full    展示内存泄露的细节,比如在代码中的位置;7. --log-file=logfile.log    将valgrind的打印信息输出到指定文件中,否则在直接标准输出;


五、说明
若有兴趣,可以看看下面的地址。里面的代码可以作为备用组件。
https://github.com/Jiacheng03/MemLeakDetector

原创粉丝点击