默认 Win32 项目具有恒定数量的内存泄漏

Posted

技术标签:

【中文标题】默认 Win32 项目具有恒定数量的内存泄漏【英文标题】:Default Win32 project has constant number of memory leaks 【发布时间】:2014-01-07 00:24:21 【问题描述】:

简介及相关资料:

我从事的原始项目有少量内存泄漏,因此我决定执行一个小测试,以便检测可能导致它们的原因。

我使用 Visual Studio 向导创建了一个 Win32 项目。 我没有添加任何内容,我只是将其保留为使用向导创建的。 我已经使用工具GDIView(http://www.nirsoft.net/utils/gdi_handles.html)查看是否有任何固有的GDI leaks

问题:

每次我调整窗口大小时,此工具都会显示我的应用程序泄漏了 +3 个区域。

我为解决问题所做的努力:

由于该项目是由 Visual Studio 向导创建的,因此我尝试从头开始创建一个简单的项目,但出现了相同的 +3 区域。

阅读 CodeProject 上有关区域的一些文章,我偶然发现了一些演示应用程序的演示应用程序。

当我打开 GDIView 时,这些应用程序也会泄漏 +3 区域。

当我打开Task Manager 以查看是否真的发生了小内存泄漏时,所有这些都得到了验证——它确实发生了,因为内存略微上升并且之后保持不变 无论我调整窗口大小多少次。

我使用 Microsoft Visual Studio 2008 Express Edition,但在常规 Visual Studio 2008 中创建空项目时也检测到问题。

我在 Windows XP 上工作,但在 Windows 7 上也会出现同样的效果。

问题:

为什么会发生这种情况以及如何消除这些小的内存泄漏?

谢谢。

最好的问候。

【问题讨论】:

'之后保持不变' - 没问题。可能不是真正的泄漏。 您是否尝试过将您的应用程序构建为控制台子系统 exe,在末尾添加键盘输入(在事件循环和窗口破坏之后),然后检查 GDI 泄漏?如果代码是通常的 Microsoft 非标准 WinMain,那么对于此测试,您可能必须告诉链接器使用入口点 winMainCRTStartup,或者将其更改为标准 main @MartinJames 但它“戳”了我的眼睛,我希望以某种方式将其移除。甚至可以删除它们,还是它们是固有的?无论我做什么,到目前为止我发现并测试过的每个编写良好的 Win32 应用程序都有这 3 个漏洞。谢谢。问候。 @Cheersandhth.-Alf,不,我没有尝试过以这种方式构建它,但我愿意尝试。您能否提供一些有关如何执行此操作的示例的链接,因为我以前没有这样做过。谢谢。问候。 @AlwaysLearningNewStuff:抱歉没有链接(我必须把它写成博客文章)。但这很简单。首先检查您是否有WinMainwWinMainmainwmain C++ 主函数。如果我没记错的话,对应的入口点(指定给链接器)是winMainCRTStartupwWinMainCRTStartupmainCRTStartupwmainCRTStartup。您必须处理此问题的原因是 Microsoft 非标准的不合理行为(例如 g++ 没有此类问题)。因此,在链接器选项中,将“subsystem”设置为“console”,将“entry”设置为调用 C++ main 的入口点函数。添加 kbd 输入。构建。 【参考方案1】:

就实际泄漏而言,这并不是真正值得担心的事情,因为它可能不是(即误报)。真正的问题是,这会影响您诊断自己的内存泄漏的能力,因为这些误报可能会“丢失”它们。

为什么会这样?

这种“泄漏”很常见。我通常使用 Qt + Linux (KDE) 来开发 GUI 应用程序,而且我总是看到非常相似的“泄漏”。问题是,在任何 GUI 软件中,您至少会有这些层:您的应用程序、GUI 库、操作系统“内核”库和图形驱动程序。以我的经验,大多数报告的“泄漏”来自图形驱动程序,大概是因为这种低级代码需要一些“黑客”,这些“黑客”可以被 Valgrind 等典型的内存诊断工具视为或检测为内存泄漏(或您正在使用的任何东西)。操作系统内核代码也可以提出类似的论点,尽管根据我的经验,从那里出来的“泄漏”要少得多(我认为他们可能会付出更多努力来避免这些“黑客攻击”)。在 GUI 库(Qt、Win32 API 等)中,出于类似的原因,也经常存在类似的“泄漏”。当然,不排除这些层中可能存在实际泄漏,但是您必须在没有泄漏的假设下工作,并且内存消耗在一段时间后稳定的事实表明它可能是至少没有真正的泄漏,没有任何可能造成损害的泄漏(例如失控的内存消耗)(顺便说一句,这种增加然后稳定的内存消耗行为是完全正常的,它与增长并最终达到平衡的堆碎片有关)。

如何消除这些小的内存泄漏?

您无法真正消除这些泄漏,特别是如果您真的与它们没有任何关系(即,它们来自 GUI 库堆栈,而不是来自您的应用程序)。您可以做的最好的事情是将这些诊断报告给负责这些库的支持和维护的任何人(例如 Microsoft),但它可能会被忽略或被视为正常发生(不是真正的泄漏)。

现在,对于真正的问题,如果您想诊断自己潜在的内存泄漏,那么您必须找到一种系统的方法来规避或忽略来自 GUI 库堆栈的“泄漏”。以下是一些典型的解决方案:

    经常检查泄漏并避免做会增加误报数量的事情(例如,调整大小)。学会“知道你的泄漏”,通过经常检查,你会熟悉来自 GUI 库堆栈的泄漏,并且能够忽略它们或从诊断中“减去”它们,只看到真实的泄漏。 使用过滤工具过滤内存诊断工具的输出。大多数检查泄漏的工具都有过滤选项来过滤(或静音)来自某些库或函数的警告或错误。您可以使用它们来消除在这些第三方库中检测到的虚假泄漏。但请注意不要过滤太多(例如,过滤掉来自 CRT 的所有泄漏),您应该保持保守(您甚至可以在代码中引入故意的内存泄漏以检查它们是否没有被过滤掉)。 模块化您的应用程序,以便大多数重要代码(繁重的代码)可以在更简单的命令行程序中运行。换句话说,把 GUI 变成一个简单的前端(这很容易做到无泄漏),它使用一些繁重的后端代码。您可以将该后端代码移植到更简单的命令行程序中,从而完全避免 GUI 库堆栈,并允许您更有效地检查内存泄漏,而不会产生所有“污染”。这是任何严肃项目的推荐解决方案,它还培养了良好的编码实践(单元测试、模块化代码、最小的相互依赖关系等)。

【讨论】:

感谢您的帮助。在执行成员 Cheersandhth.-Alf 建议的测试后,我看到所有 GDI leaks 都消失了,这让我认为您的回答是正确的。我接受它,我真诚地感谢您提供如此有教育意义的回答。 +1 来自我。最好的问候。

以上是关于默认 Win32 项目具有恒定数量的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

线程关闭期间Win64 Delphi RTL中的内存泄漏?

内存泄漏与垃圾回收机制

分析 ThreadLocal 内存泄漏问题

内存泄漏和内存溢出的区别

Android开发常见的Activity中内存泄漏及解决办法

OpenGL VBO 会泄漏内存吗?