我们有一个复杂的程序,在没有实现多线程的情况下,它可以很好地处理繁重的输入(实际上是任何输入)。我们已经实现了多线程与线程池,并给出这些输入参数,我得到这些结果:
(注意:当我说没有错误,这意味着我已经测试了valgrind -v
,当我说没有内存泄漏,这意味着我已经测试了它与valgrind --leak-check=full -v
)。
- small_file:运行成功,超过1个worker(线程),无valgrind错误,无内存泄漏
-
medium_file:使用1个worker,它运行成功,没有错误/内存泄漏。有了> 1个工人,我得到:a.通常堆腐败错误,b.双重免费。当使用
valgrind -v
和> 1个工人运行时,程序成功完成。此外,没有从valgrind(即ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
)打印错误。
现在我没有得到任何错误从valgrind开始,我能做些什么来找到内存损坏问题在这个复杂的和大的应用程序?
DevelopmentEnvironment:
Ubuntu, 64位,gcc版本:4.7.2和4.8.1(不同的计算机,更新版本的Ubuntu)。
现在我没有得到任何错误从valgrind开始,我能做些什么来找到内存损坏问题在这个复杂的和大的应用程序?
好吧,让我向你描述一下我是如何在90年代的微软JavaScript实现中发现内存泄漏的。
首先,我确保在程序的调试版本中,尽可能多的内存分配被路由到相同的helper方法。也就是说,我重新定义了malloc
、new
等,它们都是我自己编写的分配器的同义词。
这个分配器只是操作系统虚拟堆内存分配器的一个薄外壳,但它有一些额外的智能。它在块的开头和结尾分配额外的内存,并用哨兵值、迄今分配数量的线程安全计数和所有分配的线程安全双链列表填充这些内存。"自由"例程将验证双方的哨兵值仍然完好无损;如果不是,那一定是某个地方的内存损坏了。它将从链表中解除块的链接并释放它。
在任何时候,我都可以要求内存管理器按照分配的顺序列出内存中所有未完成块的列表。当DLL被卸载时,列表中留下的任何项都是内存泄漏。
这些工具使我能够很容易地实时发现内存泄漏和内存损坏。
与> 1工人,我得到:a.通常堆损坏错误,b.双重免费。当使用valgrind -v和> 1个worker运行时,程序成功完成
根据上述症状,在我看来,您的程序中显然出现了某种同步问题。看起来你的程序在线程之间共享堆内存地址,因此每当有一些数据竞争时,你就会面临问题。
您还提到,当您运行valgrind -v时,则程序成功完成。这表明您的程序有同步问题,这也依赖于序列/定时。这是最难发现的虫子之一。我们还应该记住,在程序运行并执行错误之前,动态工具不会给出任何警告。我的意思是程序中可能存在问题,但执行顺序(因为有一些与时间相关的问题)决定了工具是否会捕获这些故障。
话虽如此,我认为在大型程序中找这样的bug没有捷径。然而,我强烈怀疑有一些数据竞赛场景导致内存损坏/双自由。因此,您可能希望使用Helgrind来检查/查找可能导致内存损坏的数据竞赛/线程问题。
请使用CORE DUMP::[主要用于double-free,glibc检测到的类型错误]
使用gcc -g选项编译程序
<标题> ulimit - h1> 会显示核心文件的大小ulimit -c unlimited
它将设置核心文件的大小为无限制
现在运行你的程序,然后在你的当前目录将生成一个名为"core"
然后用GDB分析,如下所示。