FastMM 报告 C++ Builder 6 中 STL 容器的内存泄漏
Posted
技术标签:
【中文标题】FastMM 报告 C++ Builder 6 中 STL 容器的内存泄漏【英文标题】:FastMM reports memory leaks on STL containers in C++ Builder 6 【发布时间】:2016-07-05 11:15:08 【问题描述】:当我创建一个空的控制台应用程序并在其中使用 STL 容器时,FastMM 在应用程序关闭时报告内存泄漏。
例如,如果我在main()
中创建std::vector<int>
:
std::vector<int> v;
编译,运行,关闭,不报告泄漏。
如果我这样做:
std::vector<int> v;
v.push_back(100);
我明白了:
此应用程序已泄漏内存。小块泄漏是:
309 - 340 字节:未知 x 1
同样,我收到了关于以下内容的泄漏报告:
std::vector<int> v;
v.push_back(100);
v.clear();
还报告了泄漏:
std::vector<int> v;
v.reserve(1);
对于某些容器,例如std::deque
,只需创建一个容器就足够了,即使不更改其内容,应用程序关闭时也会报告泄漏。
谁能解释发生了什么?我使用 Borland C++Builder 6 和 FastMM4。我一直在更改 FastMMOptions.inc
中的各种设置,但我仍然看到报告了这些泄漏。
【问题讨论】:
Borland C++Builder 6 似乎是在 2002 年问世的......你有机会使用更现代的编译器吗?甚至是更新版本的 C++Builder?对于软件而言,14 年是一段很长的时间。 我说,因为给定代码的 sn-p,除了编译器错误的std::vector
实现之外,没有什么会导致内存泄漏(没有看到周围的上下文)。或检漏仪报告的误报。
是的,我们有 Borland XE7,新项目是在新环境中开发的。但是我需要调查现有项目中的内存泄漏,由于它们的大小,我们还没有迁移到 XE7。我发现 FastMM 非常有用,但是因为在我们的代码中很多地方都使用了 STL,所以它指出了让我非常困惑的漏洞。
@CoryKramer:有时人们无法选择使用现代编译器。我自己在日常工作中仍然使用 C++Builder 6。不是因为我想要,而是因为我的公司需要它(不是因为多年来没有尝试升级,PTB 不允许它,因为新版本更不稳定并且不能满足业务需求)。
std::deque
在 C++Builder 6 中被窃听且无法使用
【参考方案1】:
清除std::vector
不会释放用于vector
内部数组的内存,它只是破坏数组中的项目,然后将std::vector::size()
设置为0。数组本身仍然是分配的,所以它可以重复用于vector
中推送的新项目。 vector
的析构函数将释放数组。
在 C++Builder 6 中,默认的 STL 库是 STLPort(在 C++Builder 2006 中被 Dinkumware 取代)。 STLPort 对~std::vector()
的实现仅破坏了数组项(好像clear()
已被调用),但不会释放数组本身,因此您看到的是“泄漏”。根据 STLPort 网站上的以下常见问题解答,这实际上根本不是泄漏:
Q6.2 My tool detect memory leaks in application with STLport. Is this leak from STLport?
A6.2 在大多数情况下,这是某些工具错误支持的“伪内存泄漏”。
在STLport的默认编译中,节点分配器用于分配内部内存。节点分配器通过预先分配一大块内存并分发小内存块来工作。在运行使用 STLport 的应用程序期间,内存块没有被释放(即它没有返回到系统,有像 BoundsChecker、Purify 或 Valgrind 这样的工具来检查 memorytml 泄漏,对于在不再使用。当使用 STLport 的节点分配器时,这些工具可能会报告错误的内存泄漏。内存块通常在应用程序端释放,但内存检查器通常会在此之前报告内存泄漏。另一个内存问题当您使用内部使用 STLport 并静态链接到它的共享库(例如 DLL,此问题特定于 Windows DLL 模型)时可能会报告。如果内存在 dll 中分配并在另一个 dll 中释放,则 STLport 节点分配器将保留释放的内存以备将来使用。如果您不使用此内存,那么即使没有真正的内存泄漏,您的应用程序全局内存消耗也会增长直到应用程序崩溃。这就是为什么您应该始终使用连贯的配置 dll 中的所有内容或静态库中的所有内容。
有一些方法可以消除伪内存泄漏(由于内存在程序结束时被正确释放,泄漏只是伪内存)。您可以使用 STLport 中使用的另一个分配器。打开文件
"stlport/stl/_site_config.h"
并取消注释以下任一选项:_STLP_USE_NEWALLOC enables a simple allocator that uses "new/delete" _STLP_USE_MALLOC enables a simple allocator that uses "malloc/free"
new/delete 分配器具有提供跟踪内存不足的入口点的优势,有关详细信息,请参阅编译器文档中的 set_new_handler 或 C++ 标准。
您也可以定义以下符号,只需在
"stlport/stl/_site_config.h"
中取消注释即可。_STLP_LEAKS_PEDANTIC
该符号强制释放所有内存块。另请参阅配置文件中符号周围的 cmets。
请注意,如果您对文件进行任何更改,您必须重新编译 STLport 以及您的应用程序和所有依赖库!
还有一些定义有助于调试 STLport 中的内存问题。在 _STLP_DEBUG 模式下,只需在“./stlport/stl_user_config.h”或您的项目设置中定义以下符号:
_STLP_DEBUG_ALLOC _STLP_DEBUG_UNINITIALIZED
您不需要为这些选项重新构建 STLport,但如果您对文件进行任何更改,则必须重新构建您的应用程序和所有依赖库。
也就是说,在早期 C++Builder 版本中使用的 RogueWave STL 也随 C++Builder 6 一起提供,以向后兼容旧代码,并且不会遇到此问题。您可以通过在项目的条件列表中定义 _USE_OLD_RW_STL
从 STLPort 切换到 RogueWave。
【讨论】:
优秀且内容丰富的回复。定义_USE_OLD_RW_STL
后,FastMM 不会报告我们项目中使用的容器的任何泄漏(std::vector
std::list
std::deque
)。非常感谢你。现在查看内存泄漏报告要容易得多。
我注意到的另一件事是,std::cout
的任何使用都会报告泄漏。幸运的是,我们的代码中没有很多,但如果你知道另一个“神奇的条件定义”来阻止那些出现在报告中,那就太好了。示例:std::cout << "hello" << endl;
报告:13 - 20 字节:未知 x 1 21 - 36 字节:std::codecvtprintf("hello\n");
报告没有泄漏以上是关于FastMM 报告 C++ Builder 6 中 STL 容器的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
虚拟内存地址空间不足(Borland C++ Builder 6 程序)