【问题标题】:Tracing memory corruption on a production linux server跟踪生产 Linux 服务器上的内存损坏
【发布时间】:2010-11-14 01:07:57
【问题描述】:

各位,能否推荐一个用于在使用 c++ 构建并在 linux x86_64 下运行的生产多线程服务器上发现内存损坏的工具?我目前面临以下问题:每隔几个小时,我的服务器就会因段错误而崩溃,核心转储显示 malloc/calloc 中发生错误,这绝对是某处内存损坏的迹象。

实际上我已经尝试了一些工具,但运气不佳。以下是我目前的经验:

  • Valgrind 是一个很棒的(我什至可以说是最好的)工具,但它会大大降低服务器速度,使其无法在生产中使用。我在舞台服务器上尝试过,它确实帮助我找到了一些与内存相关的问题,但即使在修复它们之后,我仍然会在生产服务器上崩溃。我在 Valgrind 下运行了我的舞台服务器几个小时,但仍然没有发现任何严重的错误。

  • ElectricFence 据说是一个真正的内存猪,但我什至无法让它正常工作。它几乎立即在舞台服务器上随机奇怪的地方出现段错误,而 Valgrind 根本没有显示任何问题。也许 ElectricFence 不支持线程?...我不知道。

  • DUMA - 与 ElectricFence 的故事相同,但更糟。虽然 EF 生成了带有可读回溯的核心转储,但 DUMA 只向我显示“?????”(是的,服务器肯定是使用 -g 标志构建的)

  • dmalloc - 我将服务器配置为使用它而不是标准的 malloc 例程,但是它在几分钟后挂起。将 gdb 附加到进程表明它挂在 dmalloc 的某个位置:(

我逐渐变得疯狂,根本不知道下一步该做什么。我有以下工具可供尝试:mtrace、mpatrol 但也许有人有更好的主意?

非常感谢您对此问题的任何帮助。

更新:我设法找到了错误的根源。但是,我在舞台服务器上发现它不是使用 helgrind/DRD/tsan 的生产服务器 - 多个线程之间存在数据竞争,导致内存损坏。关键是使用适当的 valgrind 抑制,因为这些工具显示了太多的误报。仍然我真的不知道如何在生产服务器上发现它而不会显着减速...

【问题讨论】:

  • 你是编译 libefence 还是使用 LD_PRELOAD 环境变量?如果用 -DUSE_SEMAPHORE 编译,electricfence 应该是线程安全的
  • 我使用的是 libefense.a 而不是 .so。而且我没有自己编译,我在Gentoo上使用emerge安装的。您是否建议使用此标志手动安装它?
  • 可能有帮助的一件事是查看 +/- 200 字节的 seg 错误表示数据已损坏的位置。通过查看数据,您可能会了解导致内存损坏的原因。
  • 能否请您详细说明一下或提供一个链接,我可以在其中找到更多信息?我怎样才能用 gdb 做到这一点?
  • 如果异常addr的值为x,则计算y为x-200,然后在gdb中执行x/400xb y(将y替换为上面计算的地址)

标签: c++ linux memory production corruption


【解决方案1】:

你可以试试 IBM purify,但恐怕不是开源的..

【讨论】:

  • 好吧,如果没有其他办法……但我仍然相信应该有一个开源解决方案来解决这个问题。
  • 另外 purify 会大大降低应用程序的速度,并且不能在生产机器上使用。
【解决方案2】:

是的,C/C++ 内存损坏问题非常棘手。 我也使用了几次valgrind,有时它会显示问题,有时不会。

在检查 valgrind 输出时,不要太快地忽略它的结果。有时在花费相当长的时间后,你会发现 valgrind 一开始就给了你线索,但你忽略了它。

另一个建议是比较以前已知稳定版本的代码更改。如果您使用某种源版本控制系统(例如 svn),这不是问题。检查所有与内存相关的函数(例如 memcpy、memset、sprintf、new、delete/delete[])。

【讨论】:

  • 至于检查所有与内存相关的函数 - 我不会在任何地方直接使用它们,所有指针都是 shared_ptrs 或 weak_ptrs 并且所有容器都来自 stl...
  • STL 很好,但即使使用 STL,您也可能遇到内存损坏问题,例如为什么使用无效的迭代器。见angelikalanger.com/Conferences/Slides/…
  • 是的,我知道即使有这样的高级库,总是有可能在脚下开枪
【解决方案3】:

Google Perftools --- 它是开源的 --- 可能会有所帮助,请参阅 heap checker 文档。

【讨论】:

  • 不幸的是,堆检查器非常有限,它只能检测内存泄漏而不能检测内存溢出。它甚至无法检测到不匹配的 new[]/delete :(
【解决方案4】:

使用 gcc 4.1 和 -fstack-protector-all 开关编译您的程序。如果内存损坏是由堆栈粉碎引起的,这应该能够检测到它。您可能需要使用 SSP 的一些附加参数。

【讨论】:

    【解决方案5】:

    你试过-fmudflap吗? (向上滚动几行以查看可用选项)。

    【讨论】:

    • 我目前正在解决“错误:mudflap 无法跟踪未知大小的 extern '__prime_list'”错误:(知道为什么会发生它们吗?我在代码中的任何地方都没有 __prime_list 符号...
    • 它确实依赖于安装 libmudflap。也许不是?
    【解决方案6】:

    试试这个: http://www.hexco.de/rmdebug/ 我广泛使用它,它对性能的影响很小(主要影响内存量)但分配算法是相同的。它总是被证明足以找到任何分配错误。一旦出现错误,您的程序就会崩溃,并且会有详细的日志。

    【讨论】:

    • 谢谢,我去看看。我想知道它在 c++ 多线程应用程序中是否可以正常工作...
    【解决方案7】:

    伙计们,我设法找到了错误的来源。然而,我在使用 helgrind/DRD/tsan 的舞台服务器上发现了它——多个线程之间存在数据竞争,导致内存损坏。关键是使用正确 valgrind 抑制,因为这些工具显示了太多误报。仍然我真的不知道如何在生产服务器上发现它而不会显着减速...

    【讨论】:

      【解决方案8】:

      我不确定它是否会捕获您的特定错误,但 MALLOC_CHECK_ 环境变量 (malloc man page) 会在默认 Linux malloc 实现中启用额外检查,并且通常没有显着运行时成本。

      【讨论】:

      • 谢谢,我也试过了(MALLOC_CHECK_=3),但是,它没有显示我的任何内存损坏源,因为(正如我之前写的)内存被 datarace 损坏而不是由于不当使用 malloc/free...
      猜你喜欢
      • 2019-11-04
      • 1970-01-01
      • 1970-01-01
      • 2014-04-26
      • 2013-10-27
      • 2014-07-18
      • 1970-01-01
      • 1970-01-01
      • 2013-07-07
      相关资源
      最近更新 更多