1、内存泄露的检测
之前也用到了一些内存泄露的检测方法。知道大概的原理就是窜改内存分配的函数,在原始的分配基础(内存大小)上添加一些记录分配内存的信息,如文件、分配代码的行号。Windows编程中SDK、MFC提供的一些检测函数因为窜改的内存分配函数不同,所以检测的范围也不尽相同。
因为之前的工作中使用MFC来实现系统界面,所以大部分代码都是链接的MFC库,而非Windows标准库,使用内存分配的函数是new,而非malloc,所以一般都用MFC提供的DEBUG_NEW来检测。一般会在文件的开头处使用下面的宏替换(这在MFC文件中非常常见):
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
这样在程序中使用new就会被DEBUG_NEW代替,DEBUG_NEW重载了new,所以在程序结束时,检测分配链表是否为空,非空则打印出相应的泄露代码行。
在afx.h中,定义DEBUG_NEW:
// Memory tracking allocation
void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
#define DEBUG_NEW new(THIS_FILE, __LINE__)
注意的是,此处DEBUG_NEW 仅仅只是替换new,所以只对new的内存分配具有作用,不能检测malloc分配的内存。另外,DEBUG_NEW替换了new,重载了函数,对那些本身就重载了new的类会有影响,使其不能正确的调用合适的new函数,发生错误,使用时也应格外小心这一点。
以前虽然知道Windows提供了一些CRT的DEBUG方法类检测内存泄露,但一直没有使用过,前段时间找工作时,有被人问到,最近工作中看到公司的一些原来的代码中也有所使用。
#ifdef _DEBUG
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
#endif
具体参考MSDN:
Call _CrtSetDbgFlag with newFlag equal to _CRTDBG_REPORT_FLAG to obtain the current _crtDbgFlag state
然后设置_CRTDBG_LEAK_CHECK_DF,这样就可以检测内存泄露问题了。
使用注意,需要加载头文件#include <crtdbg.h>,这样可以对malloc和new分配的内存同时检测。
2、特殊宏
宏的使用可以帮助有效定位,错误发生的位置,MSVC中一般在Output窗口中输出文件名(代码行),双击该条目即可定位。
一般可写为TRACE(".......%s(%d)", __FILE__, __LINE__);
之前转载的文章《C/C++语言宏定义技巧》中有提到过这些宏(如_ L I N E _ 、_ F I L E _ 、_ D A T E _ 、_ T I M E _ 、_ S T D C _ ),具体可翻阅相关编译器资料,今天提到一个新的宏__FUNCTION__来获取函数名,据说VC6不支持,未尝试过,使用时应该注意编译器的版本和支持情况。
3、NT服务程序调试
之前一直没有写过NT服务的后台程序,最近负责查看一个NT服务程序,所以需要调试。在自己没有想到办法的时候,只能求助于MSDN和网络。网络搜索还是比较快捷的,抄在下面:
调试 Windows 服务应用程序
http://msdn.microsoft.com/en-us/aa984342(zh-cn,VS.71).aspx
- 安装您的服务。有关更多信息,请参见安装和卸载服务。
- 可从服务控制管理器、“服务器资源管理器”或代码启动服务。有关更多信息,请参见启动服务。
- 在 Visual Studio 中,从“调试”菜单中选择“进程”。
出现“进程”对话框。
- 单击“显示系统进程”。
- 在“可用进程”区域内单击服务的进程,然后单击“附加”。
提示 此进程将与服务的可执行文件同名。
出现“附加到进程”对话框。
- 选择任意适当选项,然后单击“确定”关闭对话框。
注意 您现在已处于调试模式。
- 设置要在代码中使用的任意断点。
- 访问服务控制管理器并操纵您的服务,并发送停止、暂停和继续命令以命中您的断点。有关运行服务控制管理器的更多信息,请参见启动服务。