API调用获取进程的当前堆大小?

时间:2016-12-12 03:26:47

标签: c++ c linux heap-memory

我正在调试大型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();
}

2 个答案:

答案 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)执行的内存分配信息以及相关信息   功能。 …

  • malloc_hook
      

    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)munmapmprotect(2)(和旧的sbrk(2)system call s可以更改您的虚拟地址空间。 C ++ new使用malloc,而后者经常使用mmap。但是,freedelete通常将释放的内存区域标记为将来的malloc-s可重用,但不会将内存放弃给系统。

PS。如果valgrind无法正常工作,我想您已经损坏了内存,这不仅比内存泄漏还糟。考虑尝试使用某种消毒剂(和其他instrumentation),也许是address sanitizer。当然,启用所有警告和调试信息(因此编译with g++ -Wall -Wextra -g),并花一些时间来改进源代码以完全获得 no 警告。最新的GCC编译器(于2018年8月发布了GCC 8)比旧版本提供了更好的警告并改进了清除程序,因此值得更新g++编译器。