如何在 C++ 中跟踪内存分配(尤其是新建/删除)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/438515/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to track memory allocations in C++ (especially new/delete)
提问by Anteru
How can I track the memory allocations in C++, especially those done by new
/delete
. For an object, I can easily override the operator new
, but I'm not sure how to globally override all allocations so they go through my custom new
/delete
. This should be not a big problem, but I'm not sure how this is supposed to be done (#define new MY_NEW
?).
我如何跟踪 C++ 中的内存分配,尤其是那些由new
/完成的分配delete
。对于对象,我可以轻松覆盖operator new
,但我不确定如何全局覆盖所有分配,以便它们通过我的自定义new
/ delete
。这应该不是什么大问题,但我不确定应该如何完成(#define new MY_NEW
?)。
As soon as this works, I would assume it's enough to have a map somewhere of pointer/location of the allocation, so I can keep track of all allocations which are currently 'active' and - at the end of the application - check for allocations which have not been freed.
一旦这可行,我会假设在分配的指针/位置的某处有一个映射就足够了,这样我就可以跟踪当前“活动”的所有分配,并且 - 在应用程序结束时 - 检查分配哪些还没有被释放。
Well, this seems again like something that surely has been done several times at least, so any good library out there (preferably a portable one)?
好吧,这似乎又像是肯定至少已经做过几次的事情,那么有没有好的库(最好是便携式的)?
采纳答案by Johannes Schaub - litb
I would recommend you to use valgrind
for linux. It will catch not freed memory, among other bugs like writing to unallocated memory. Another option is mudflap, which tells you about not freed memory too. Use -fmudflap -lmudflap
options with gcc, then start your program with MUDFLAP_OPTIONS=-print-leaks ./my_program
.
我建议你使用valgrind
linux。它将捕获未释放的内存,以及其他错误,例如写入未分配的内存。另一种选择是mudflap,它也告诉您未释放的内存。使用-fmudflap -lmudflap
带有 gcc 的选项,然后使用MUDFLAP_OPTIONS=-print-leaks ./my_program
.
Here's some very simple code. It's not suitable for sophisticated tracking, but intended to show you how you would do it in principle, if you were to implement it yourself. Something like this (left out stuff calling the registered new_handler and other details).
这是一些非常简单的代码。它不适合复杂的跟踪,但旨在向您展示如果您要自己实现它,原则上您将如何进行。像这样的东西(省略了调用注册的 new_handler 和其他细节的东西)。
template<typename T>
struct track_alloc : std::allocator<T> {
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;
template<typename U>
struct rebind {
typedef track_alloc<U> other;
};
track_alloc() {}
template<typename U>
track_alloc(track_alloc<U> const& u)
:std::allocator<T>(u) {}
pointer allocate(size_type size,
std::allocator<void>::const_pointer = 0) {
void * p = std::malloc(size * sizeof(T));
if(p == 0) {
throw std::bad_alloc();
}
return static_cast<pointer>(p);
}
void deallocate(pointer p, size_type) {
std::free(p);
}
};
typedef std::map< void*, std::size_t, std::less<void*>,
track_alloc< std::pair<void* const, std::size_t> > > track_type;
struct track_printer {
track_type * track;
track_printer(track_type * track):track(track) {}
~track_printer() {
track_type::const_iterator it = track->begin();
while(it != track->end()) {
std::cerr << "TRACK: leaked at " << it->first << ", "
<< it->second << " bytes\n";
++it;
}
}
};
track_type * get_map() {
// don't use normal new to avoid infinite recursion.
static track_type * track = new (std::malloc(sizeof *track))
track_type;
static track_printer printer(track);
return track;
}
void * operator new(std::size_t size) throw(std::bad_alloc) {
// we are required to return non-null
void * mem = std::malloc(size == 0 ? 1 : size);
if(mem == 0) {
throw std::bad_alloc();
}
(*get_map())[mem] = size;
return mem;
}
void operator delete(void * mem) throw() {
if(get_map()->erase(mem) == 0) {
// this indicates a serious bug
std::cerr << "bug: memory at "
<< mem << " wasn't allocated by us\n";
}
std::free(mem);
}
int main() {
std::string *s = new std::string;
// will print something like: TRACK: leaked at 0x9564008, 4 bytes
}
We have to use our own allocator for our map, because the standard one will use our overridden operator new, which would result in an infinite recursion.
我们必须为我们的地图使用我们自己的分配器,因为标准分配器将使用我们覆盖的运算符 new,这将导致无限递归。
Make sure if you override operator new, you use the map to register your allocations. Deleting memory allocated by placement forms of new will use that delete operator too, so it can become tricky if some code you don't know has overloaded operator new not using your map, because operator delete will tell you that it wasn't allocated and use std::free
to free the memory.
确保如果您覆盖 operator new,您使用地图来注册您的分配。删除由 new 的放置形式分配的内存也将使用该 delete 运算符,因此如果您不知道的某些代码重载了 operator new 而不使用您的映射,这可能会变得棘手,因为运算符 delete 会告诉您它没有分配并且用于std::free
释放内存。
Also note, as Paxpointed out for his solution too, this will only show leaks that are caused by code using our own defined operator new/delete. So if you want to use them, put their declaration in a header, and include it in all files that should be watched.
另请注意,正如Pax在他的解决方案中指出的那样,这只会显示由使用我们自己定义的运算符 new/delete 的代码引起的泄漏。因此,如果您想使用它们,请将它们的声明放在标题中,并将其包含在所有应注意的文件中。
回答by Necro
To be specific, use valgrind's massif tool. As opposed to memcheck, massif is not concerned with illegal use of memory, but tracking allocations over time. It does a good job of 'efficiently' measuring heap memory usage of a program. The best part is, you don't have to write any code. Try:
具体来说,使用 valgrind 的 massif 工具。与 memcheck 不同,massif 不关心内存的非法使用,而是随着时间的推移跟踪分配。它在“有效”测量程序的堆内存使用方面做得很好。最好的部分是,您不必编写任何代码。尝试:
http://valgrind.org/docs/manual/ms-manual.html
http://valgrind.org/docs/manual/ms-manual.html
Or if you are really impatient:
或者如果你真的不耐烦:
valgrind --tool=massif <executable> <args>
ms_print massif.out.<pid> | less
This will give you a graph of allocations over time, and back traces to where the big allocations ocurred. This tool is best run on Linux, I don't know if there is a Windows varient. It doeswork on OS X.
这将为您提供随时间推移的分配图,并追溯大分配发生的位置。这个工具最好在Linux上运行,不知道有没有Windows版本。它确实适用于 OS X。
Good luck!
祝你好运!
回答by paxdiablo
You can use the code at http://www.flipcode.com/archives/How_To_Find_Memory_Leaks.shtmlwith the following modifications: the code as given only works if you have one big honkin' source file. I sorted this out for another question on SO (here).
您可以使用http://www.flipcode.com/archives/How_To_Find_Memory_Leaks.shtml上的代码并进行以下修改:给定的代码仅在您有一个大的 honkin' 源文件时才有效。我为另一个关于 SO (这里) 的问题整理了这个。
For a start, don'tchange stdafx.h, make your modifications in your own files.
首先,不要更改 stdafx.h,在您自己的文件中进行修改。
Make a separate header file mymemory.h and put your function prototypes in it, for example (note that this has no body):
例如,创建一个单独的头文件 mymemory.h 并将您的函数原型放入其中(请注意,它没有body):
inline void * __cdecl operator new(unsigned int size,
const char *file, int line);
Also in that header, put the other prototypes for AddTrack(), DumpUnfreed(), etc., and the #defines, typedef and the extern statement:
同样在该头文件中,放置 AddTrack()、DumpUnfreed() 等的其他原型,以及 #defines、typedef 和 extern 语句:
extern AllocList *allocList;
Then, in a new mymemory.cpp (which also #include's mymemory.h), put the actual definition of allocList along with all the real functions (not just the prototypes) and add that file to your project.
然后,在新的 mymemory.cpp(也是 #include 的 mymemory.h)中,将 allocList 的实际定义与所有实际函数(不仅仅是原型)一起放入,并将该文件添加到您的项目中。
Then, #include "mymemory.h"
in every source file in which you need to track memory (probably all of them). Because there are no definitions in the header file, you won't get duplicates during the link and because the declarations are there, you won't get undefined references either.
然后,#include "mymemory.h"
在您需要跟踪内存的每个源文件中(可能是所有源文件)。因为头文件中没有定义,所以在链接过程中你不会得到重复,而且因为声明在那里,你也不会得到未定义的引用。
Keep in mind that this won't track memory leaks in code that you don't compile (e.g., third-party libraries) but it should let you know about your own problems.
请记住,这不会跟踪您未编译的代码(例如第三方库)中的内存泄漏,但它应该让您了解自己的问题。
回答by Timo Geusch
Well, you can re-implement the global operators new and delete to give you the functionality you want, but I'd advise against that unless this is the only way to track memory allocations, due to restrictions of your platform for example.
好吧,您可以重新实现全局运算符 new 和 delete 以提供您想要的功能,但我建议不要这样做,除非这是跟踪内存分配的唯一方法,例如由于您的平台的限制。
Memory debuggers are available for most of the common development platforms. Have a look at PurifyPlusfor a commercial solution that works on Windows and various Unixes or valgrindfor an open source one that works on Linux (and potentially other operating systems but I've only ever used it on Linux).
内存调试器可用于大多数常见的开发平台。看看PurifyPlus是一种适用于 Windows 和各种 Unix 的商业解决方案,或者是一种适用于 Linux(可能还有其他操作系统,但我只在 Linux 上使用过它)的开源解决方案的valgrind。
If you are intent on replacing the global operators, have a look at this article.
如果您打算替换全局运算符,请查看本文。
回答by Damien
For our Windows platform C++ projects, I use VLD, Visual Leak Detector, which is almost too easy to implement that tracks and reports on memory leaks when your application exits - best of all its free and the source is available. The system can be setup to report in a number of ways (disk logger, IDE, XML etc) and has been invaluable for detecting leaks in Windows Services which are always a challenge to debug. So whilst you are looking for a portable solution, if you wish to roll your own you can of course view the source for guidance. Hope it helps.
对于我们的 Windows 平台 C++ 项目,我使用 VLD,Visual Leak Detector,它几乎太容易实现,它可以在您的应用程序退出时跟踪和报告内存泄漏——最重要的是它是免费的,并且源代码可用。该系统可以设置为以多种方式报告(磁盘记录器、IDE、XML 等),并且对于检测 Windows 服务中的泄漏非常宝贵,这些泄漏一直是调试的挑战。因此,当您正在寻找便携式解决方案时,如果您想推出自己的解决方案,您当然可以查看指导源。希望能帮助到你。
To quote the site:
引用该网站:
It's a very effective way to quickly diagnose, and fix, memory leaks in C/C++ applications.
这是在 C/C++ 应用程序中快速诊断和修复内存泄漏的一种非常有效的方法。
回答by Ashley Davis
If you develop under Windows the free tool DebugDiag will help find memory and handle leaks.
如果您在 Windows 下开发,免费工具 DebugDiag 将帮助查找内存和处理泄漏。
You don't need to augument your program for DebugDiag to work.
您不需要为 DebugDiag 工作而扩充您的程序。
Although it is not the easiest or most intuitive program to use! Make sure you google for tutorials and instructions on how to use it.
虽然它不是最容易使用或最直观的程序!确保您在谷歌上搜索有关如何使用它的教程和说明。
回答by user52875
On Linux, there's at least two traditional methods:
在 Linux 上,至少有两种传统方法:
- malloc() and free() (and other memory-related functions) are weak symbols, which means that you can simply reimplement them and your versions will be used. For an implementation example: see electric fence.
- With the LD_PRELOAD environment variable, you can override symbols (both weak and strong) symbols in shared libraries with the symbols found in the libraries contained in the LD_PRELOAD environment variable. If you compile a shared library with malloc(), free() and friends, you're all set. Again, electric fence demonstrates this.
- malloc() 和 free()(以及其他与内存相关的函数)是弱符号,这意味着您可以简单地重新实现它们并使用您的版本。有关实施示例:请参阅电围栏。
- 使用 LD_PRELOAD 环境变量,您可以使用包含在 LD_PRELOAD 环境变量中的库中的符号覆盖共享库中的符号(弱和强)符号。如果您使用 malloc()、free() 和朋友编译共享库,那么您就大功告成了。电围栏再次证明了这一点。
As such, you don't only catch new and delete, but also the C-style memory allocation functions. I haven't done this on windows yet, but I've seen methods to rewrite how DLLs are linked there too (although I recall they were kind of clumsy).
因此,您不仅可以捕获 new 和 delete,还可以捕获 C 风格的内存分配函数。我还没有在 Windows 上这样做过,但我已经看到了重写 DLL 链接方式的方法(尽管我记得它们有点笨拙)。
Note however that apart from the fact that these are interesting techniques, I'd recommend to use valgrind to do what you want above anything else.
但是请注意,除了这些是有趣的技术这一事实之外,我建议您使用 valgrind 来做您想做的事情。
回答by gimpf
Not directly answering your question, but if you really just want to get a list of leaked heap-objects at the end of the program, you may well just run the program with valgrind.
不直接回答您的问题,但如果您真的只想在程序结束时获得泄漏的堆对象列表,您可能只需使用valgrind运行该程序。
For MS VS you may play with the Debug CRT Heap. Not as simple as valgrind, a bit too much to explain here, but may do what you want.
对于 MS VS,您可以使用Debug CRT Heap。不像valgrind那么简单,在这里解释有点太多,但可以做你想做的。
回答by Dmytro Voloshyn
If I need a tool I usually start from what my compiler/standard library provides.
如果我需要一个工具,我通常从我的编译器/标准库提供的东西开始。
- If you use glibc you can use mtrace. It installs a global hook that logs every glibc memory allocation function (malloc, realloc, memalign, free, and everything implemented on top of them like new/delete)
- If you use Microsoft CRT you can look at CRT Debug Heap Details. There are examples how to install debug version of memory allocation functions, getting heap statistics, finding memory leaks, etc.
- 如果您使用 glibc,您可以使用mtrace。它安装了一个全局钩子,记录每个 glibc 内存分配函数(malloc、realloc、memalign、free 以及在它们之上实现的所有内容,如 new/delete)
- 如果您使用 Microsoft CRT,您可以查看CRT 调试堆详细信息。有示例如何安装调试版本的内存分配函数、获取堆统计信息、查找内存泄漏等。
回答by Dhia Hassen
Check this tiny handy code , now instead of new
use NEW
and track all allocations in the NewHelper
constructor :
检查这个小巧方便的代码,现在而不是new
使用NEW
和跟踪NewHelper
构造函数中的所有分配:
#include <iostream>
class NewHelper
{
private :
void* addr = nullptr;
public :
NewHelper(void * addr_)
{
addr = addr_;
std::cout<<addr<<std::endl;
}
template <class T>
operator T ()
{
return (T)addr;
}
};
#define NEW (NewHelper)(void*)new
int main()
{
int * i = NEW int(0);
return 0;
}