【问题标题】:finding the caller of a constructor in C++在 C++ 中找到构造函数的调用者
【发布时间】:2010-10-05 09:17:58
【问题描述】:

寻找一种快速而肮脏的方法来识别构造函数的调用者(或任何与此相关的函数)我正在编写宏来通过将this 指针转储到OutputDebugString 来帮助识别内存泄漏。

了解 ctor 和 dtor 的调用位置有助于识别问题。

tnx \0

【问题讨论】:

  • "OutputDebugString" 听起来像一个 Windows API 函数。我建议添加一个“windows”或类似的标签。

标签: c++ windows memory-leaks


【解决方案1】:

如果您使用的是 Visual Studio,则可以附加调试器,而不是让断点有一个跟踪点。为此,您可以右键单击断点并选择When Hit...。然后选择打印包含堆栈跟踪的消息。此消息将发送到输出窗格,您可以在闲暇时分析所有呼叫。

【讨论】:

    【解决方案2】:

    感谢大家的反馈。由于即使在程序的短暂生命周期中也有数百次调用新对象,所以在 ctor 中设置断点不是一种选择。

    在 ctor 和 dtor 中跟踪宏就可以了。

    Visual Leak Detector 和 Stackwalk64 看起来很有前途

    还发现 AfxDumpStack(AFX_STACK_DUMP_TARGET_ODS); // 输出调试字符串
    但是很吵

    【讨论】:

    • 欢迎来到 Stack Overflow! :) 通常在您的问题中添加这些感谢和总结。答案是按投票排序的,所以这里的 cmets 可能看起来有点格格不入。如果您认为给定的答案是“正确的”,则习惯上将答案标记为已接受。玩得开心:)
    【解决方案3】:

    您似乎在 Windows (OutputDebugString) 上。因此,您可以使用 StackWalk64 api 来获取堆栈跟踪。 有关详细信息,请参阅“Printing the stack trace in C++ (MSVC)”问题。

    还有很多泄漏检测工具可用(BoundsChecker 等)。

    【讨论】:

      【解决方案4】:

      基本上你不会,而是保存所有分配/解除分配并发现谁没有释放对象/区域。

      看到这个答案
      Heap corruption under Win32; how to locate?

      锁好。

      【讨论】:

        【解决方案5】:

        如果您使用的是 g++,则可以构建您的项目以进行覆盖。当您运行一些示例代码时,您可以使用gcov 查看程序的覆盖率。

        此输出包括调用树,您应该能够看到对构造函数的调用以及调用它们的函数。

        我能想到的唯一缺点是您只能获得实际执行的代码的输出,因此您需要有良好的测试用例。话虽如此,无论如何执行覆盖率分析都是值得的。最后,强烈推荐大家使用lcov查看结果!

        【讨论】:

          【解决方案6】:

          建议使用调试器和调用堆栈是合理的,可能是最好的解决方案。但是,如果您没有调试器,那将无济于事。

          您知道构造函数使用的calling convention 吗?如果是这样,您可以使用一些内联汇编器(如果您的编译器支持它)来检查函数调用的顺序。使用 std 调用(Win32 最常见的约定),弹出堆栈将显示指向函数调用后要返回的地址的指针(即调用函数中的某个位置)。这并不理想,但是您可以从该点向后退,直到到达您知道是函数开始的地址。这里唯一的问题是您需要获取所有函数的地址才能执行此操作......这可以使用一个简单的技巧来完成,将 eip 的值放入函数顶部的另一个寄存器中,然后将此值移动到一个数组中,以便稍后在调试时进行检查,例如(intel 语法):

          call label
          label:
          pop eax
          mov [address of next array entry], eax
          

          【讨论】:

            【解决方案7】:

            我能想到的最好的方法是在调试器中运行你的程序并在构造函数中放置一个断点。接下来,检查调用堆栈。

            如果您想针对一个特定类中的一个特定分配,您可以保留分配计数并查看哪个分配编号没有被释放。再次运行程序,并在正确的分配号上中断。


            如果您需要将调用堆栈转储到日志中,我知道可以使用例如 win32 API 生成堆栈转储。更通用的方法是将显式调用堆栈保持为全局/线程特定状态,例如在std::vector<std::string>-object 中。 (使用RAII确保每个push_back都伴随着一个pop_back

            【讨论】:

            • 如果该构造函数被多次调用并且只有一个调用函数忘记整理......
            • graham.reeds:是的。我添加了一小段关于使用分配计数器的内容。
            【解决方案8】:

            您在 Windows 下运行? Visual Leak Detector 过去曾帮助我找到内存泄漏。

            使用RAII 也有助于减少内存泄漏。

            如果您喜欢冒险,那么您可以重载新功能和删除功能。 Paul Nettle does this in his MMGR.

            【讨论】:

              【解决方案9】:

              如果您使用的是 Linux,那么 Valgrind 可以满足您的所有需求,甚至更多。在使用 C++ 进行开发时,我发现它是必不可少的。

              【讨论】:

                【解决方案10】:

                使用 gcc?为什么不generate a stack trace

                【讨论】:

                  【解决方案11】:

                  你能操纵 ctor 和 dtor 吗?我不是 C++ 开发人员,您应该很容易看到这一点,但也许在这种情况下,您可以将调用者的引用传递给构造函数。

                  【讨论】:

                    【解决方案12】:

                    对此没有快速而肮脏的方法,C++ 不提供任何可移植的方法来查看堆栈跟踪。如果您想搜索内存泄漏,我建议您查看valgrind 和类似工具,它们做得很好。作为编码准则,首先使用 RAII 避免内存泄漏(资源始终拥有所有者)。

                    【讨论】:

                    • 无意冒犯,但我不明白你是如何得出这样的结论的要便携 :)
                    猜你喜欢
                    • 2023-01-23
                    • 2015-03-17
                    • 1970-01-01
                    • 2021-12-22
                    • 2010-09-25
                    • 1970-01-01
                    • 2018-05-25
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多