C++编码中减少内存缺陷的方法和工具
数IsBadReadPtr、IsBadWritePtr、IsBadStringPtr、IsBadCodePtr用来检测指针指向的内存区域是否可读/写。C运行时库提供了_CrtIs ValidPointer、_CrtIsValidHeapPointer等函数,MFC库提供了AfxIsValidAddress、AfxIsValidString函数来完成类似功能。
(2)对基于MFC的程序,ASSERT_VALID宏通过调用重载的AssertValid函数来确定指向CObject派生类对象的指针是否有效。ASSERT_VALID宏主要调用了AfxIsValidAddress函数和CObject派生类对象的AssertValid函数(参考MFC源代码afx.h、objcore.cpp)。 2.2 利用C运行时刻库检查内存泄漏 VC++的C运行库(CRT)提供了广泛的功能,帮助用户检测内存泄漏。CRT提供了_CrtMemCheckPoint、_CrtDump MemoryLeaks、_CrtSetDbgFlag等函数来帮助调试内存泄漏。 对于非MFC的工程, 要开启有效的内存泄漏报告功能, 需要进行如下设置: (1)在StdAfx.h的头部添加如下代码并开启编译器/Yu 选项:
(2)确保在每个.cpp文件的头部包含以下内容:
(3)在程序的开始处开启报告内存泄漏的开关: _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF); 对于MFC工程, MFC已经做了相关的工作, 只需要确认在每个.cpp文件的头部包含上述第(2)点的内容。 在某些情况下,需要知道发生内存泄漏的内存块中的内容,但是标准的内存转储只是内存块头部的十六进制形式。为了得到更多的有用信息,需要以用户块类型(_CLIENT_ BLOCK)申请内存,并利用_CrtSetDumpClient建立用户块型内存的转储函数。具体的说,对于不是从CObject继承的类,需要: (1)为每个类/结构指定一个用户块子类型(参考crtdbg.h)。 (2)在申请内存时,采用重载的new形式:void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine)(参考MFC源代码 afxmem.cpp),其中nType就是用户块的子类型。 (3)创建一个用户块内存转储函数,专门对每种需要转储的子类型进行处理(需要包含dbgint.h)。 (4)利用_CrtSetDumpClient对用户块内存转储函数进行注册(参考MFC源代码dumpinit.cpp)。 对于从CObject继承来的类,MFC 已经按照上述方法做了基础工作(参考MFC源代码 afxmem.cpp、dumpinit.cpp)。要有效转储从CObject继承的对象,需要:(1)对每个从CObject继承的类重载虚函数Dump。(2)在程序的初始化部分 加入代码 afxDump.SetDepth(1)来开启深度转储。 2.3 利用Purify和Insure++查找运行时内存缺陷 Rational Purify和Parasoft Insure++ 是用于运行时错误检查的工具。Purify主要检测:数组内存越界读/写,使用未初始化的内存,对已释放的内存进行读/写,内存泄漏等。Insure++利用其专利技术(源码插装和运行时指针跟踪)能够发现大量的内存操作错误,报告错误的源代码行和执行轨迹。根据笔者的测试(基于98个有各种内存错误的C++程序,涵盖了典型情形),Insure++ 6.1都能准确检测。 3 利用VC++环境的调试和诊断功能,检查和发现常见内存缺陷 理解常见的内存缺陷问题以及在VC++环境下的症状,能辅助我们减少问题的发生和及时修改问题。 从错误的表现形式上看, 和堆栈有关的错误主要分为两大类:堆栈溢出和函数返回信息被破坏。 (1)堆栈溢出(overflow) 此类错误主要有两种情形: 1)过大的局部变量。缺省情况下Windows为每个线程保留1M堆栈空间。在菜单Project->Properties->Configuration Properties -> Linker->System中可以看到 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |