我有一个长期运行的C ++程序,通常用gcc(g ++)编译。我使用valgrind来验证没有内存泄漏,所以我不是在寻找泄漏检测器。
但我关注的是临时缓冲区/对象上的内存碎片和不必要的新/删除对。
有没有办法记录所有对new的调用(即使它们发生在STL容器内),提供堆栈跟踪以便我可以在代码中搜索它们?我尝试过mtrace,但这只适用于C ++ - 它最终说当我查找负责的代码行时,所有分配都发生在全局新的分配器中。不知怎的,valgrind的memcheck几乎可以做我想要的,因为它显示了内存分配的堆栈跟踪。不幸的是,它们似乎只是在没有匹配解除分配的情况下为分配而呈现。
答案 0 :(得分:6)
如果您想跟踪有关分配的其他统计信息,您可以随时覆盖全局新/删除功能:
void* operator new (size_t size)
{
void *pPtr = alloc_memory(size); /* perform the allocation here but don't use new! */
if(pPtr == 0)
throw std::bad_alloc();
/* additional code here to do whatever sort of tracking you want */
return pPtr;
}
void operator delete (void *pPtr)
{
if(pPtr == 0)
return; // legal to call delete on NULL pointers - don't pass NULL to free()
/* additional code to do whatever tracking you want here */
free(pPtr);
}
至于获得回溯,那就是编译器和O / S依赖,并且没有标准的方法来实现它。由于您提到GCC,以下内容可能对您有用:
http://tombarta.wordpress.com/2008/08/01/c-stack-traces-with-gcc/
答案 1 :(得分:1)
我赞成Nik B.'s answer指向我正确的方向,而这正是我实际使用libunwind
做的事情,因为链接的堆栈跟踪建议只能获取链接库的函数名称。此代码可在GitHub的https://github.com/landtuna/opnew-stacktraces
newdelete.cpp:
#include <exception>
#include <new>
#include <cstdlib>
#include <iostream>
#include "stacktrace.hpp"
void* operator new (size_t size) {
void* p = malloc(size);
if (p == 0) {
throw std::bad_alloc();
}
std::cout << "allocated " << size << std::endl;
printTrace(std::cout);
return p;
}
void operator delete (void* p) {
free(p);
}
stacktrace.cpp:
#include <cxxabi.h>
#include <libunwind.h>
#include <ostream>
#include <cstdlib>
#include <cstring>
using namespace std;
#include "stacktrace.hpp"
void printTrace(ostream& out) {
unw_cursor_t cursor;
unw_context_t context;
unw_getcontext(&context);
unw_init_local(&cursor, &context);
while (unw_step(&cursor) > 0) {
unw_word_t offset, pc;
char fname[200];
size_t demangledSize = 200;
char* demangled = (char*) malloc(demangledSize);
unw_get_reg(&cursor, UNW_REG_IP, &pc);
fname[0] = '\0';
unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);
int status;
char *ret = abi::__cxa_demangle(fname, demangled, &demangledSize, &status);
if (ret) {
// return value may be a realloc() of the input
demangled = ret;
}
else {
// demangling failed, just pretend it's a C demangled with no args
strncpy(demangled, fname, demangledSize);
strncat(demangled, "()", demangledSize);
demangled[demangledSize-1] = '\0';
}
out << hex << demangled << "+0x" << offset << " [" << pc << "]" << dec << '\n';
free(demangled);
}
out << endl;
}