【问题标题】:How to trace dynamically loaded libraries with Valgrind?如何使用 Valgrind 跟踪动态加载的库?
【发布时间】:2025-12-28 20:15:06
【问题描述】:

我有一个使用dlopendlclose 加载/卸载库的进程。该库有一些我想用 Valgrind 跟踪的内存泄漏。我尝试了以下方法:

LD_PRELOAD=libmylibrary.so valgrind --leak-check=full myprogram

它不起作用。我得到一个未定义的符号错误,因为库依赖于主程序中的一些符号。有没有其他方法可以让库在程序结束时保持加载?

【问题讨论】:

  • 您使用什么操作系统?如果您预加载,您会观察到什么?

标签: shared-libraries valgrind


【解决方案1】:

这是一个老问题,但我相信如果他/她偶然发现它,这可以帮助将来的人。

您可以将--keep-debuginfo=yes 参数传递给valgrind:

--keep-debuginfo= [默认:no]

启用后,保留(“归档”)符号和所有其他调试信息以用于卸载代码。这 允许保存的堆栈跟踪包含已被 dlclose'd 的代码的文件/行信息(或 相似的)。请注意这一点,因为它可能导致程序无限使用内存 重复加载和卸载共享对象。

某些工具和某些功能仅对存档调试信息提供有限支持。 Memcheck 完全支持它。通常,报告错误的工具可以使用存档的调试信息 显示错误堆栈跟踪。已知的限制是: Helgrind 过去的访问堆栈跟踪 竞争条件不使用存档的调试信息。 Massif(以及更普遍的 xtree Massif 输出格式)不使用存档的调试信息。只有 Memcheck 已经(有点)经过测试 使用 --keep-debuginfo=yes,所以其他工具可能有未​​知的限制。

【讨论】:

    【解决方案2】:

    只需跳过测试程序中的 dlclose(),以便共享对象的代码段将保存在进程的内存映射表中。然后当 valgrind 发现任何由这个共享对象引起的泄漏时,它可以从进程的内存映射表中找到符号名称。

    如果调用 dlclose(),dl 库可能会从进程的内存空间中卸载共享对象,那么 valgrind 将无法将地址解析为有意义的符号名称。

    此外,使用 LD_PRELOAD= 加载带有调试信息的库。

    【讨论】:

    • 我无法控制是否调用dlclose。我该如何解决这个问题?
    • 这是一个老话题,我记得尽可能多地写。我编写了一个测试程序,它直接调用 dlopen 来加载我的测试代码并使用 Valgrind 来检查内存泄漏。直接调用dlopen是为了防止操作系统触发dll卸载导致内存泄漏。
    • 对于其余的细节,也许你可以看看这个例子:gist.github.com/tailriver/30bf0c943325330b7b6a
    • 感谢您的回复!