我建议你在linux下使用valgrind
。它会捕获不释放的内存,以及写入未分配内存等其他错误。另一个选择是mudflap,它告诉你关于没有释放内存。使用gcc使用-fmudflap -lmudflap
选项,然后用MUDFLAP_OPTIONS=-print-leaks ./my_program
启动程序。
这里有一些非常简单的代码。它不适用于复杂的跟踪,但打算向您展示如果您要自己实现它,原则上如何实现。像这样的东西(省略了调用注册的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
}
我们必须用我们自己的分配器为我们的地图,因为标准的人会用我们的重载运算符new,这将导致无限递归。
确保您是否覆盖operator new,使用map来注册您的分配。删除由新的布局形式分配的内存也将使用该删除操作符,因此如果某些代码不知道已经重载了operator new而不使用您的映射,那么它会变得棘手,因为操作符delete会告诉您它没有被分配,使用std::free
释放内存。
还请注意,因为Pax也指出他的解决方案,所以只会显示由使用我们自己定义的运算符new/delete的代码导致的泄漏。所以如果你想使用它们,把他们的声明放在一个头文件中,并将其包含在所有应该被监视的文件中。
没有通用的现成答案。请提供有关所用操作系统和平台的更多信息。 – kauppi 2009-01-13 10:59:36
我需要一个至少可以在Linux和Windows上运行的解决方案,并且最好在Mac OS上运行。 – Anteru 2009-01-13 12:27:40