使用/不使用 Visual Leak Detector 在 C++ 中检测内存泄漏
我想检测我的 C++ 程序在 Windows 中的内存泄漏.我也在 MSDN 上阅读了关于 的文档mermoy 泄漏检测,我也开始使用 Visual Leak Detector.
我对泄漏的报告有疑问.我期待一个带有行号的文件名,但我总是报告下面的文本.它具有泄漏描述的所有组成部分(块类型、内存地址、数据等.)除了文件名和行号.
如果是真的泄露?如果是,您知道为什么没有报告文件/行吗?与此同时,我也在查看 这个网址
谢谢
<前>检测到内存泄漏!转储对象 ->{4723} 位于 0x04AFB5B8 的普通块,8 字节长.数据:2C 3F 00 00 28 3F 00 00{1476} 位于 0x04AC3B58 的普通块,12 字节长.数据:00 CD CD CD EB 01 75 4C CA 3D 0B 00对象转储完成. 解决方案我研究了许多不同的跟踪内存泄漏的方法.它们都有自己的优点,也有缺点.
要了解它们的优缺点,我们必须了解不同的机制和要求:
new、delete、malloc、free是如何截取的?一些工具使用 #define 来重新定义 new、delete、malloc 和 free,但这依赖于包含文件的正确顺序,如果类包含例如一种称为 free 的方法(如 Qt 中的情况).预处理器也会重新定义这个方法,这可能会导致编译错误或无法解析的外部.
另一种方法是否决全局 new 和 delete 运算符.这是一个更简洁的解决方案,但失败的是您有一个 3rd 方库,它在库中放置了一个新库,但在标题中删除了(反之亦然).
如何确定呼叫的来源.如果 new,delete,... 是使用 #define's 截获的,通常预处理器符号
__FILE__
和__LINE__
用于获取泄漏源.但是,如果您的代码中有通用"功能,例如CreateString(),那么大部分的泄露都会报在这些泛型函数中,其实对你帮助不大.另一种方法是在运行时获取调用堆栈.使用 Windows StackWalk 函数可以很容易地完成,但根据我的经验,这非常非常慢.一个更快的替代方法是直接获取基指针,并依赖堆栈帧指针(您必须使用/Oy- 进行编译以获取堆栈帧指针).您可以像这样获取框架(基)指针:_asm
mov DWORD PTR [FramePtr], ebp
.然后简单地循环并在循环中从((ADDR *)FramePtr)[1];
和下一个帧指针从FramePtr = ((ADDR *)FramePtr)[0];
如何及时报告泄漏.就我而言,我希望在应用程序结束时报告泄漏,但为了能够做到这一点,您需要在应用程序结束时使用泄漏报告机制.这意味着如果你想自己报告你的泄漏,你需要依赖在你的应用程序结束时被销毁的全局变量(并在全局变量的析构函数中报告泄漏).对于服务器类型的应用程序,您可能更感兴趣的是获取两个时间点之间的内存使用差异.
现在是不同的泄漏系统:
C RunTime:最后报告泄漏,但没有像样的报告调用堆栈的方法.其拦截对 new、delete、... 调用的方法可能会在与 3rd 方库(如 Qt、Boost 等)结合使用时出现问题
外部 Microsoft 实用程序(如 GFlags、UMDH、...):它们似乎只能记录两个时间点之间的差异.然而,调用堆栈似乎要好得多,尽管 GFlags 实用程序可能会在操作系统中设置标志,这可能会导致您的应用程序严重减速.
视觉检漏仪.似乎正确地找到了所有泄漏,但在我的情况下它不起作用,因为我有一个 3rd 方 DLL,它只是在其 DllUnload 处中止进程(似乎是 Windows 7 特定问题).
我个人最喜欢的(我敢肯定,人们不会同意我的观点)是编写自己的内存管理器.使用全局new 和delete 操作符可以很容易地完成拦截(有上面提到的可能的问题),你可以像上面描述的那样获取调用堆栈.这种替代方案还依赖于能够在应用程序的最后时刻执行代码.
在选择替代方案时,我发现以下方面对我的情况非常重要:
- 我希望它在我的应用程序中无缝运行,以便在发生泄漏时立即通知每个开发人员.如果您将泄漏检查推迟到稍后使用 Purify 等外部实用程序时,泄漏查找将更加困难.
- 我希望在应用程序结束时自动报告泄漏.
- 我想从泄漏中获得尽可能多的信息(数据、调用堆栈等)
希望这会有所帮助.
I want to detect memory leaks of my C++ program in Windows. I read the documentation also on MSDN about mermoy leak detection and I also started using Visual Leak Detector.
I have a doubt about the reporting of the leaks. I am expecting a file name with a line number, but I am always reported the text below. It has all the component of a leak description ( block type, memory address, data, etc..) except for the file name and the line number.
If it is a real leak? If yes do you know why the file/line are not reported? In the meantime I am having a look also at this url
Thanks
Detected memory leaks! Dumping objects -> {4723} normal block at 0x04AFB5B8, 8 bytes long. Data: 2C 3F 00 00 28 3F 00 00 {1476} normal block at 0x04AC3B58, 12 bytes long. Data: 00 CD CD CD EB 01 75 4C CA 3D 0B 00 Object dump complete.
解决方案
I investigated quite some different ways of tracking memory leaks. They all have their advantages but also their disadvantages.
To understand their advantages and disadvantages, we have to understand the different mechanisms and requirements:
How are new, delete, malloc and free intercepted? Some tools use #define to redefine new, delete, malloc and free, but this relies on the correct order of the include files, and may give problems if a class contains e.g. a method called free (as is the case in Qt). The preprocessor will also redefine this method, which may lead to compilation errors or unresolved externals.
Another way is to overrule the global new and delete operators. This is a much cleaner solution, but fails is you have a 3rd party library that puts a new in the library, but the delete in the header (or vice versa).
How is the source of the call determined. If new,delete,... are intercepted using #define's, often the preprocessor symbols
__FILE__
and__LINE__
are uses to get the source of the leak. However, if you have 'generic' functions in your code like e.g. CreateString(), then most of the leaks will be reported in these generic functions, which does not really help you.An alternative is to get the call stack at run time. It can be quite easily done using the Windows StackWalk function, but in my experience, this is very very slow. A much faster alternative is to get the base-pointer directly, and to rely on the stack-frame-pointers (you must compile with /Oy- to get the stack-frame-pointers). You can get the frame (base) pointer like this: _asm
mov DWORD PTR [FramePtr], ebp
. Then simply loop and in the loop get the instruction pointer from((ADDR *)FramePtr)[1];
and the next frame-pointer fromFramePtr = ((ADDR *)FramePtr)[0];
How to report the leaks at the exact moment. In my case, I want the leaks to be reported at the end of the application, but to be able to do this, you need a leak-reporting mechanism at the end of your application. This means that if you want to report your leaks yourself, you need to rely on global variables being destructed at the end of your application (and report the leaks in ths destructor of the global variable). For server-type applications, you are probably more interested in getting the difference in memory usage between two points in time.
And now the different leak-systems:
C RunTime: reports leaks at the end, but has no decent way of reporting call stacks. Its method of intercepting calls to new,delete,... may cause problems in combinations with 3rd party libraries (like Qt, Boost, ...)
External Microsoft utilities (like GFlags, UMDH,, ...): they seem to be able to only log differences between two points in time. However, the call stack seems to be much better, although the GFlags utility may set flags in the OS that may cause a serious slowdown of your application.
Visual Leak Detector. Seems to correctly find all leaks, but in my case it doesn't work since I have a 3rd party DLL that simply aborts the process at its DllUnload (seems to be a Windows 7 specific problem).
My personal favorite (and people will not agree with me, I'm sure), is to write your own memory manager. Intercepting can be easily done using global new and delete operators (with the possible problems mentioned above), and you can get the call stack as described above. This alternative also relies on being able to have code that is executed at the very last moment in your application.
When choosing an alternative, I found the following aspects very imporant for my situation:
- I want it to work seemlessly in my application, so that every developer is notified immediately if there is a leak. If you delay leak-checking to a later moment where you use external utilities like Purify, leak-finding will be much harder.
- I want leaks to be reported at the end of the application, automatically.
- I want as much as possible information from the leak (the data, the call stack, ...)
Hope this helps.
相关文章