問題描述
我如何在 C++ 中跟蹤內(nèi)存分配,尤其是那些由 new
/delete
完成的.對(duì)于對(duì)象,我可以輕松覆蓋 operator new
,但我不確定如何全局覆蓋所有分配,以便它們通過我的自定義 new
/delete代碼>.這應(yīng)該不是什么大問題,但我不確定應(yīng)該如何完成(
#define new MY_NEW
?).
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
?).
只要這可行,我就會(huì)假設(shè)在分配的指針/位置的某處有一個(gè)映射就足夠了,這樣我就可以跟蹤當(dāng)前活動(dòng)"的所有分配,并且 - 在應(yīng)用程序結(jié)束時(shí) -檢查尚未釋放的分配.
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.
嗯,這似乎又是一件肯定至少已經(jīng)做過幾次的事情,所以有什么好的圖書館(最好是便攜式的)?
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)?
推薦答案
我建議你使用 valgrind
for linux.它將捕獲未釋放的內(nèi)存,以及其他錯(cuò)誤,例如寫入未分配的內(nèi)存.另一種選擇是mudflap,它也告訴您未釋放的內(nèi)存.在 gcc 中使用 -fmudflap -lmudflap
選項(xiàng),然后使用 MUDFLAP_OPTIONS=-print-leaks ./my_program
啟動(dòng)你的程序.
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
.
這是一些非常簡(jiǎn)單的代碼.它不適合復(fù)雜的跟蹤,但旨在向您展示原則上如何進(jìn)行,如果您要自己實(shí)現(xiàn)它.像這樣的東西(省略了調(diào)用注冊(cè)的 new_handler 和其他細(xì)節(jié)的東西).
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).
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
";
++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
";
}
std::free(mem);
}
int main() {
std::string *s = new std::string;
// will print something like: TRACK: leaked at 0x9564008, 4 bytes
}
我們必須為我們的地圖使用我們自己的分配器,因?yàn)闃?biāo)準(zhǔn)分配器將使用我們覆蓋的運(yùn)算符 new,這將導(dǎo)致無限遞歸.
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.
確保如果您覆蓋 operator new,您使用映射來注冊(cè)您的分配.刪除由 new 的放置形式分配的內(nèi)存也將使用該 delete 運(yùn)算符,因此如果您不知道的某些代碼重載了 operator new 而不使用您的映射,這可能會(huì)變得棘手,因?yàn)檫\(yùn)算符 delete 會(huì)告訴您它沒有分配并且使用 std::free
釋放內(nèi)存.
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.
另請(qǐng)注意,正如 Pax 在他的解決方案中指出的那樣,這只會(huì)顯示由使用我們自己定義的運(yùn)算符 new/delete 的代碼引起的泄漏.因此,如果您想使用它們,請(qǐng)將它們的聲明放在標(biāo)題中,并將其包含在所有應(yīng)注意的文件中.
Also note, as Pax pointed 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.
這篇關(guān)于如何在 C++ 中跟蹤內(nèi)存分配(尤其是新建/刪除)的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!