FastMM报告c++ Builder 6中STL容器的内存泄漏

FastMM reports memory leaks on STL containers in C++ Builder 6

本文关键字:内存 泄漏 STL 报告 c++ Builder FastMM      更新时间:2023-10-16

当我创建一个空控制台应用程序并在其中使用STL容器时,FastMM在应用程序关闭时报告内存泄漏。

例如,如果我在main()中创建一个std::vector<int>:

std::vector<int> v;

编译,运行并关闭,无泄漏报告。

如果我这样做:

std::vector<int> v;
v.push_back(100);

:

应用程序内存泄漏。小块泄漏为:

309 - 340 bytes: Unknown 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的各种设置,但我仍然看到这些泄漏报告。

清除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我的工具检测内存泄漏与STLport应用程序。这是从STLport泄露的吗?

在大多数情况下,这是一些工具错误支持的"伪内存泄漏"。

在STLport的默认编译中,使用节点分配器分配内部内存。节点分配器通过预先分配大块内存并分发小内存块来工作。内存块在运行使用STLport的应用程序期间不释放(即它不返回到系统,有像BoundsChecker, Purify或Valgrind这样的工具来检查内存泄漏,当不再使用时不释放的内存。当使用st_port的节点分配器时,这些工具可能会报告错误的内存泄漏。内存块通常在应用程序结束时释放,但内存检查器通常在该点之前报告内存泄漏。当您使用共享库(例如DLL,此问题特定于Windows DLL模型)内部使用STLport并静态链接到它时,可能会报告另一个内存问题。如果内存在一个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"

新的/delete分配器的优点是提供了一个跟踪内存耗尽的入口点,有关更多信息,请参阅编译器文档或c++标准中的set_new_handler。

或者您可以定义以下符号,只需在"stlport/stl/_site_config.h"中取消注释即可。

_STLP_LEAKS_PEDANTIC

符号强制释放所有内存块。也可以查看配置文件中符号周围的注释。

请注意,如果对文件进行任何更改,您必须重新编译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。