我正在调试大型C ++应用程序中的慢速内存泄漏,我想在程序的各个点打印出当前堆大小。
除了打开和解析/proc/PID/statm
之外,是否有任何库API调用可以从中获取此信息?
但是,有一篇文章建议sbrk()
返回当前堆指针 - 不是我想要的100%。 (第二个问题:sbrk()
值的变化是否与当前堆大小的变化相对应?)
我看了,但似乎很奇怪,没有系统调用...
由于
更新我
我在调用sbrk()
和阅读proc/.../statm
之间进行了一些测试比较。 sbrk()
似乎不反映实际分配。相反,似乎statm
测量实际分配,而sbrk()
显示总堆大小。
这个整体大小的增量大块(等于页面大小?)。
下面的测试程序会根据sbrk()
报告的/proc/.../statm
和内存使用量生成此输出(堆大小),清楚地显示差:
0 ALLOC: HEAP SIZE: 0
MEMORY USAGE: 1308 201 174 2 0 566 0
1 ALLOC: HEAP SIZE: 135168
MEMORY USAGE: 1565 212 184 2 0 823 0
2 ALLOC: HEAP SIZE: 135168
MEMORY USAGE: 1822 216 187 2 0 1080 0
3 ALLOC: HEAP SIZE: 135168
MEMORY USAGE: 2079 217 187 2 0 1337 0
4 ALLOC: HEAP SIZE: 135168
MEMORY USAGE: 2336 218 187 2 0 1594 0
5 ALLOC: HEAP SIZE: 135168
MEMORY USAGE: 2593 219 187 2 0 1851 0
0 FREE: HEAP SIZE: 135168
MEMORY USAGE: 3364 225 189 2 0 2622 0
1 FREE: HEAP SIZE: 135168
MEMORY USAGE: 3107 224 189 2 0 2365 0
2 FREE: HEAP SIZE: 135168
MEMORY USAGE: 2850 223 189 2 0 2108 0
3 FREE: HEAP SIZE: 135168
MEMORY USAGE: 2593 222 189 2 0 1851 0
4 FREE: HEAP SIZE: 135168
MEMORY USAGE: 2336 221 189 2 0 1594 0
5 FREE: HEAP SIZE: 135168
MEMORY USAGE: 2079 220 189 2 0 1337 0
测试计划
class CfgProfileList
{
public:
bool obtainSystemProfileList();
void leakObjTest();
std::set<std::string> mProfileList;
private:
char dummy[1024 * 1024]; // use up some space
};
class ComUtil
{
public:
static void printMemoryUsage();
private:
static unsigned int mHeapOrigin;
};
/* static */
unsigned int ComUtil::mHeapOrigin = 0;
// Print current process memory utilization
/* static */ void
ComUtil::printMemoryUsage()
{
unsigned int pHeap = (unsigned int)sbrk(0);
if (mHeapOrigin == 0)
mHeapOrigin = pHeap;
printf("HEAP SIZE: %u\n", pHeap - mHeapOrigin);
char fname[256], line[256];
sprintf(fname, "/proc/%d/statm", getpid());
FILE *pFile = fopen(fname, "r");
if (!pFile)
return;
fgets(line, 255, pFile);
fclose(pFile);
printf("MEMORY USAGE: %s", line);
}
void
CfgProfileList::leakObjTest()
{
CfgProfileList *pointerList[50];
int n = 10;
int sleep = 100000;
printf("OBJECT ALLOCATION\n");
for (int i = 0; i < n; i++)
{
pointerList[i] = new CfgProfileList;
printf("%d ALLOC: ", i);
ComUtil::printMemoryUsage();
usleep(sleep);
}
printf("\n");
for (int i = 0; i < n; i++)
{
delete pointerList[i];
printf("%d FREE: ", i);
ComUtil::printMemoryUsage();
usleep(sleep);
}
}
int
main(int argc, char **argv)
{
CfgProfileList pl;
pl.leakObjTest();
}
答案 0 :(得分:5)
由于glibc的display: inline-block;
position: absolute;
top: calc(50% - 60px);
left: calc(50% - 60px);
基于new
,因此可以使用malloc信息和调试功能;例如,您可以在应用程序中添加一个malloc_stats()
的调用。
malloc()
malloc_stats ()函数(在出现标准错误时)打印有关以下项分配的内存的统计信息: malloc (3)和相关功能。 …
您也可以看看
mallinfo()
,
mallinfo ()函数返回一个结构的副本,该结构包含有关 malloc (3)执行的内存分配信息以及相关信息 功能。 …
GNU C库允许您修改 malloc (3), realloc (3)的行为和 free (3)通过指定适当的挂钩函数。您可以使用这些挂钩来帮助调试使用动态内存分配的程序,以便 例子。
mtrace()
。
mtrace ()函数为内存分配函数( malloc (3), realloc (3) > memalign (3), 免费(3))。这些挂钩函数记录有关内存分配和释放的跟踪信息。跟踪信息可用于发现 内存泄漏并尝试释放程序中未分配的内存。
答案 1 :(得分:1)
我正在调试大型C ++应用程序中的缓慢内存泄漏
您应该尝试使用valgrind(在用-g
编译所有代码之后)。这是一个很好的跟踪内存泄漏的工具(但是它确实会使您的程序变慢,可能至少是x3或x10)。
我想在程序的各个位置打印出当前堆大小。
我不确定堆大小是否具有明确定义的含义(但请参见您问题的其他答案)。该操作系统提供并管理virtual address space中的process,其中的某些部分通常称为“堆”。您可以使用proc(5)和parse(从程序内部)/proc/self/stat
,/proc/self/statm
,/proc/self/status
,/proc/self/maps
,这可以很快。还要使用pmap(1),ps(1),top(1)命令(内部全部使用/proc/
)。 mmap(2)和munmap
,mprotect(2)(和旧的sbrk(2))system call s可以更改您的虚拟地址空间。 C ++ new
使用malloc
,而后者经常使用mmap
。但是,free
或delete
通常将释放的内存区域标记为将来的malloc
-s可重用,但不会将内存放弃给系统。
PS。如果valgrind
无法正常工作,我想您已经损坏了内存,这不仅比内存泄漏还糟。考虑尝试使用某种消毒剂(和其他instrumentation),也许是address sanitizer。当然,启用所有警告和调试信息(因此编译with g++ -Wall -Wextra -g
),并花一些时间来改进源代码以完全获得 no 警告。最新的GCC编译器(于2018年8月发布了GCC 8)比旧版本提供了更好的警告并改进了清除程序,因此值得更新g++
编译器。