为啥 _CrtSetDumpClient 不起作用?
Posted
技术标签:
【中文标题】为啥 _CrtSetDumpClient 不起作用?【英文标题】:Why is _CrtSetDumpClient not working?为什么 _CrtSetDumpClient 不起作用? 【发布时间】:2014-08-04 23:56:46 【问题描述】:我正在使用 Visual Studio Express 2013 for Windows Desktop 编写一个用 C 语言编写的 Windows 命令行程序。在调试模式下编译时,我真的希望我的程序能够检测内存泄漏并将它们打印在标准错误或标准输出上,以便它们出现在我的面前。
通过调用_CrtDumpMemoryLeaks,我可以将内存泄漏信息打印到 Visual Studio 中的调试输出(您可以在输出窗格下找到)。根据 MSDN 文档,我认为我可以添加对 _CrtSetDumpClient 的调用,以便访问被转储的数据,然后将其打印到 stderr。
这是我用来测试这个问题的代码:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <stdio.h>
#include <crtdbg.h>
void dumpClient(void * userPortion, size_t blockSize)
printf("memory leak: %d\n", blockSize);
int main(int argc, char ** argv)
printf("hello\n");
_CrtSetDumpClient(&dumpClient);
malloc(44);
_CrtDumpMemoryLeaks();
return 0;
我在 Visual Studio 中创建了一个新的 Visual C++ Win32 控制台应用程序项目,将此代码粘贴到项目中,禁用预编译头文件,确保 IDE 处于调试模式,然后构建。如果我按 F5 (开始调试命令)运行它,那么我可以在 Visual Studio 的调试窗口中看到以下输出,这很好:
Detected memory leaks!
Dumping objects ->
c:\users\david\documents\scraps\test_vc++\testvc\testvc.cpp(15) : 81 normal block at 0x0120A500, 44 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
The program '[3868] TestVC.exe' has exited with code 0 (0x0).
但是,如果我在 dumpClient
中设置断点,我可以看到它永远不会被调用。此外,如果我从命令提示符运行程序,它只会打印hello
。我希望看到的预期输出是:
hello
memory leak: 44
有谁知道为什么 dumpClient
函数根本没有被调用?
【问题讨论】:
您创建了一个“正常”泄漏,而不是您的代码标记为“客户端”分配的特殊泄漏。通过 _CrtSetReportHook() 挂钩报告正常泄漏。 【参考方案1】:TL;DR
你可以打电话给_malloc_dbg(44, _CLIENT_BLOCK, filename, line)
而不是malloc
。
通过查看 dbgheap.c,您可以看到调用函数的唯一方法是:
if (_BLOCK_TYPE(pHead->nBlockUse) == _CLIENT_BLOCK)
_RPT3(_CRT_WARN, "client block at 0x%p, subtype %x, %Iu bytes long.\n",
(BYTE *)pbData(pHead), _BLOCK_SUBTYPE(pHead->nBlockUse), pHead->nDataSize);
if (_pfnDumpClient && !__crtIsBadReadPtr(pbData(pHead), pHead->nDataSize))
(*_pfnDumpClient)((void *)pbData(pHead), pHead->nDataSize);
else
_printMemBlockData(plocinfo, pHead);
所以你必须有 _BLOCK_TYPE(pHead->nBlockUse) == _CLIENT_BLOCK。
调用malloc
时,只分配_NORMAL_BLOCK
s。
您可以改为致电_malloc_dbg(44, _CLIENT_BLOCK, filename, line)
。
http://msdn.microsoft.com/en-us/library/faz3a37z.aspx
然后你的函数将被调用。
当然,Microsoft 可以在 _CrtSetDumpClient
文档中提到这一点,但这太容易了 ;)
【讨论】:
谢谢!如果我查看 crtdbg.h(Visual Studio 附带),我可以看到malloc(s)
是如何定义为 _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
的。我想知道他们为什么那样做。我还看到他们对free(s)
做了类似的事情,所以我可能必须为 malloc 制作我自己的预处理器宏,并免费让它正常工作。
仅供参考,dbgheap.c 可以在C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src
找到【参考方案2】:
根据 MSDN documentation
_CrtSetDumpClient: Installs an application-defined function to
dump _CLIENT_BLOCK type memory blocks
这里的关键字是 _CLIENT_BLOCK。此处记录了各种类型的 blocks on heap。一个简单的 malloc 调用会创建一个 _NORMAL_BLOCK,因此不会调用您的函数。
【讨论】:
以上是关于为啥 _CrtSetDumpClient 不起作用?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 PHP $_SESSION 变量在 header() 方法中使用时不起作用?