【问题标题】:Is there a handle leak detector which can be linked into an existing application?是否有可以链接到现有应用程序的手柄检漏仪?
【发布时间】:2011-11-22 08:11:20
【问题描述】:

我参与了各种 C++ 项目(主要使用 MSVC6 到 MSVC10),其中我们最近发现了一些句柄泄漏(CreateThread 函数给出的线程句柄)。我怀疑还有很多其他手柄被泄露,我想在我们的夜间测试结果中集成一个测试,以验证没有手柄泄露。

我的想法是开发一个 DLL,用于检测相关的 kernel32.dll 函数(CreateThread、OpenProcess、CreateProcess 等等)以及CloseHandle 函数。然后,DLL 将为每个获取的句柄记住一个回溯。在进程结束时,DLL 将打印所有未关闭到某种日志文件的句柄的回溯,然后可以由测试框架解析。

这当然也会为所有仍可访问的句柄产生回溯(所以从技术上讲,它们没有泄漏 - 也许作者打算在进程终止时让操作系统回收它们)但我想明确地关闭它们不会伤害 - 特别是因为我们已经有一些很好的 RAII 包装器用于这些东西,我们只是没有尽可能多地使用它。

现在我想知道 - 这似乎是一种相当简单的方法;也许这里有人知道已经这样做的图书馆?

【问题讨论】:

    标签: c++ winapi memory-leaks


    【解决方案1】:

    这绝对是可能的,但我认为还没有一个库可以做到这一点。

    我认为最简单的方法是使用 Application Verifier。您可以从 Microsoft 的Debugging Tools for Windows 获得它。将其配置为跟踪您的应用程序的句柄,在调试器中运行您的应用程序一段时间,然后当您的应用程序退出时,将转储一个句柄列表。

    在没有应用程序调试器的情况下,另一种方法是在应用程序退出之前设置断点或暂停。在应用程序暂停时,使用 Process Explorer 之类的工具来获取所有打开的句柄的列表。

    出于您的目的,我认为后者会是更好的选择。我不确定是否有任何使用调试输出的自动化工具。您可以使用 WDK 的某些功能来检索当前进程(或另一个进程的)打开句柄的列表,但这有点复杂。

    【讨论】:

    • 应用程序验证器看起来很不错!不幸的是,我似乎无法让它产生任何有用的结果。即使在明显泄漏句柄的测试用例应用程序中,它也不会发现任何错误或警告(即使我在ntsd 调试器下运行应用程序)。 :-/
    • 您确定配置正确吗?也许尝试测试内存泄漏以仔细检查。我不熟悉ntsd,但我认为它只对 JIT 调试有用。也许尝试使用 windbg 或附加的 Visual Studio 调试器运行您的应用程序。
    • 对于应用程序验证程序的第一步,您应该阅读:geekswithblogs.net/akraus1/archive/2010/06/25/140610.aspx
    【解决方案2】:

    Mark Russinovich 在他的系列Pushing the Limits of Windows中解释了如何更好地处理handles 以及如何跟踪句柄泄漏。

    他提到了 Windows 调试器和应用程序验证器,并解释了如何使用它来跟踪您的句柄泄漏。

    在同一页面中,他还提到了他著名的 Process Explorer 的一个简洁功能,该功能在创建/关闭句柄的过程中闪烁绿色和红色。

    【讨论】:

    • 感谢您指出这一点!我不知道Pushing the Limits of Windows,但它看起来很有趣。
    • 他描述的使用 Process Explorer 检测多个进程之间泄漏的原理 + 调试它们的方式不止一次地救了我
    • 答案中的链接已损坏。我认为这是一面镜子:techcommunity.microsoft.com/t5/windows-blog-archive/…
    【解决方案3】:

    如果您阅读了推动 Windows 的限制文章,那么您会看到它提到了 WinDbg !htrace 扩展,我认为它满足了您检测与句柄创建相关的相关 kernel32.dll 函数的第一个要求。

    要自动调用 !htrace,您可以将调试器引擎嵌入到您的测试工具中,或者您可以使用 PyDbgEng 之类的东西来启动您的应用程序并调用 !htrace 扩展,然后在应用程序完成时收集堆栈。有一个使用 PyDbgEng 进行此类自动化的示例,但在 http://pydbgeng.svn.sourceforge.net/viewvc/pydbgeng/trunk/PyDbgEng/Examples/RegMon.py?view=markup 处使用注册表函数,但我认为您可以使用此示例调用扩展,请参阅示例中的 (dbg.idebug_control.CallExtension)。

    【讨论】:

      【解决方案4】:

      我们在我目前的工作场所使用 Memory Validator。它可以配置为跟踪每个内存分配、COM 调用(和引用计数)和句柄。您启动它,然后让它启动您需要验证的代码或附加到您要验证的运行代码。从那时起,它就会跟踪您告诉它跟踪的任何资源。当代码退出时,它将报告它正在跟踪的任何未取消分配的资源,以及它们被分配的位置。它是一种商业产品,但它确实有试用期,因此您可以对其进行测试,看看它是否满足您的需求。当我们在复杂情况下遇到麻烦的泄漏时,它对我自己和同事有所帮助,但它本身并不是一个神奇的解决方案。仍然需要遵循良好的泄漏搜寻技术,它只是为您提供有关哪些分配仍然存在以及它们来自何处的更多信息。

      【讨论】:

        【解决方案5】:

        我玩过Deleaker 并在内存和句柄泄漏方面取得了成功。它可以在 Visual Studio 中使用,也可以单独使用。来自 Deleaker 网站:

        无论发生什么类型的泄漏,Deleaker 都能找到它们: 内存泄漏(由堆、虚拟内存或 OLE 分配器产生) 等)、GDI 泄漏、Windows USER 对象和句柄的泄漏。”

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-11-07
          • 2016-12-27
          • 2015-07-31
          • 2012-06-23
          • 2012-01-23
          • 2018-01-12
          • 2016-07-10
          相关资源
          最近更新 更多