一尘不染

是否有办法仅查看生成的核心文件来定位进程的哪一部分使用了大部分内存?

linux

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

后来,由于高内存使用率并生成了一个核心转储-
大约2GB,该过程崩溃了。但是问题是,我无法重现该问题,因此valgrind在这里无济于事(我想)。这种情况很少发生,我无法“抓住”。

因此,我的问题是-有没有办法使用exe和核心文件来定位过程的哪一部分使用了大部分内存?

我用来查看了核心文件gdb,没有什么异常。但是核心很重要,因此必须有一些东西。有没有一种聪明的方法来了解发生了什么,或者只是猜测可能会有所帮助(但是对于这么大的exe
..,有12个线程,大约50-100个(可能更多)类,等等,等等)

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


阅读 215

收藏
2020-06-07

共1个答案

一尘不染

以十六进制格式(作为字节/字/ dwords /
qwords)打开此核心转储。从文件的中间开始,尝试注意任何重复的模式。如果找到任何内容,请尝试确定起始地址和某些可能的数据结构的长度。使用此结构的长度和内容,尝试猜测可能是什么。使用该地址,尝试找到一些指向此结构的指针。重复直到您进入堆栈或某个全局变量。如果使用堆栈变量,您将很容易知道此链从哪个函数开始。对于全局变量,至少要知道其类型。

如果您在核心转储中找不到任何模式,则泄漏结构的可能性很大。只需将文件中看到的内容与程序中所有大型结构的可能内容进行比较即可。

更新资料

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

词语“ 仅使用智能指针
”使我感到恐惧。如果这些智能指针的重要部分是共享指针(shared_ptr,intrusive_ptr等),则与其搜索大型容器,不如搜索共享指针周期。

更新2

尝试确定堆在corefile中结束的位置(brk值)。在gdb下运行coredumped进程并使用pmap命令(从其他终端)。gdb也应该知道这个值,但是我不知道该怎么问…如果大多数进程的内存都在上方brk,则可以通过较大的内存分配(很可能是std
:: vector)来限制搜索。

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

  • 读取coredump文件,将每个值解释为一个指针(忽略代码段,未对齐的值以及指向非堆区域的指针)。对列表进行排序,计算相邻元素的差异。
  • 此时,整个内存将拆分为许多可能的结构。计算结构大小的直方图,删除任何无关紧要的值。
  • 计算这些指针所属的指针和结构的地址差。对于每种结构大小,计算指针位移的直方图,然后再次删除所有无关紧要的值。
  • 现在,您有足够的信息来猜测结构类型或构造结构的有向图。查找该图的源节点和周期。您甚至可以像在“列出“冷”存储区”中一样可视化该图。

Coredump文件为elf格式。从其标头仅需要数据段的开始和大小。为了简化过程,只需将其读取为线性文件,忽略结构即可。

2020-06-07