我建議你在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