有没有一种方法来定位进程的哪一部分使用大部分内存,只查看生成的核心文件?

我有一个进程(每次都由一个看门狗启动,因为某种原因停止了),通常使用大约200MB的内存。 一旦我看到它正在吃掉内存 – 内存使用量约为1.5-2GB,这肯定意味着某处出现了“内存泄漏”(引用中的“内存泄漏”,因为这不是真正的内存泄漏 – 像分配的内存一样,从来没有释放过无法访问 – 请注意, 只有智能指针被使用 ,所以,我想一些巨大的容器(我没有find)或类似的东西)

后来,进程崩溃,因为内存使用率高,产生了一个核心转储 – 大约2GB。 但问题是,我不能重现这个问题,所以valgrind不会在这里帮助(我猜)。 这很less发生,我不能“抓住”它。

所以,我的问题是 – 有没有办法,使用EXE和核心文件,来定位进程的哪一部分,已经使用了大部分的内存?

我用gdb看了一下核心文件,没有什么不寻常的。 但核心是大的,所以一定有一些东西。 有一个聪明的方法来了解发生了什么,或者只有猜测可能有帮助(但对于这样的大EXE .. 12线程,大约50-100(可能更多)类等等)

这是一个在RHEL5U3上运行的C++应用程序。

Solutions Collecting From Web of "有没有一种方法来定位进程的哪一部分使用大部分内存,只查看生成的核心文件?"

以十六进制格式打开此核心转储(以字节/字/双字/ qwords)。 从文件的中间开始,尝试注意任何重复模式。 如果发现任何东西,尝试确定一些可能的数据结构的起始地址和长度。 使用这个结构的长度和内容,试着猜测它可能是什么。 使用地址,尝试找到一些指向这个结构的指针。 重复,直到你来到堆栈或一些全局变量。 在堆栈变量的情况下,你会很容易知道这个链条开始的功能。 在全局变量的情况下,你至少知道它的类型。

如果在Coredump中找不到任何图案,可能是泄漏的结构非常大。 只需将文件中看到的内容与程序中所有大型结构的可能内容进行比较即可。

更新

如果你的coredump有有效的调用堆栈,你可以从检查其功能开始。 搜索任何不寻常的东西 检查调用堆栈顶部附近的内存分配是否不要求太多。 检查调用堆栈函数中可能的无限循环。

单词“ 只用智能指针 ”吓倒了我。 如果这些智能指针的重要部分是共享指针(shared_ptr,intrusive_ptr,…),而不是搜索大容器,则搜索共享指针周期是值得的。

更新2

尝试确定堆的核心文件( brk值)在哪里结束。 在gdb下运行coredumped进程,并使用pmap命令(从其他终端)。 GDB也应该知道这个值,但我不知道如何去问它…如果大多数进程的内存高于brk ,那么可以通过大内存分配来限制搜索(很可能是std :: vector)。

为了提高在现有核心堆堆中发现泄漏的机会,可以使用一些编码(我自己并没有这样做,只是一个理论):

  • 读取coredump文件,将每个值解释为一个指针(忽略代码段,未对齐值和指向非堆区域的指针)。 对列表进行排序,计算相邻元素的差异。
  • 此时整个内存被分割成许多可能的结构。 计算结构尺寸的直方图,删除任何微不足道的值。
  • 计算这些指针所属的指针和结构的地址差异。 对于每个结构大小,计算指针位移的直方图,再次丢弃任何不重要的值。
  • 现在你有足够的信息来猜测结构类型或者构造有向图的结构。 查找此图的源节点和周期。 你甚至可以将这个图形看作是在“列表”中冷的“内存区域” 。

Coredump文件是elf格式。 只有头部需要数据段的起始和大小。 为了简化过程,只需将其读作线性文件,忽略结构。

一旦我看到它正在吃掉内存 – 内存使用约1.5-2GB

很多时候这是错误循环误入歧途的最终结果。 就像是:

 size_t size = 1; p = malloc(size); while (!enough_space(size)) { size *= 2; p = realloc(p, size); } // now use p to do whatever 

如果在某些情况下, enough_space()错误地返回false,您的进程将迅速增长以消耗所有可用的内存。

只有智能指针被使用

除非您控制链接到流程中的所有代码,否则以上声明是错误的 。 错误循环可能在libc里面,或者你不拥有的任何其他库中。

只有猜测可能有帮助

这是非常多的。 Evgeny的答案有很好的出发点来帮助你猜测。

正常的内存分配器不会跟踪进程的哪个部分分配内存 – 毕竟,内存将被释放,指针由客户端代码保存。 如果内存真的泄露了(即没有指向它的指针),那么你已经迷失了方向,正在寻找一大块非结构化的内存。

Valgrind可能会发现几个可能的错误,值得分析一下。 你需要创建一个压缩文件,像这样使用--suppressions=/path/to/file.supp 。 对于valgrind标记的每个可能的错误,可以向抑制文件添加一个子句,或者改变你的程序。

你的程序在Valgrind运行速度会比较慢,所以事件发生的时间将会不同,所以你不能确定发生错误。

valgrind有一个名为Alleyoop的图形用户界面(GUI),但我没有太多用处。