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

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

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

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

std::vector<int> v;

编译,运行并关闭,未报告任何泄漏。

如果我这样做:

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

我得到:

This application has leaked memory. The small block leaks are:

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() 已被调用)但不会释放数组本身,因此您看到的是 "leak"。根据 STLPort 网站上的以下常见问题解答,这实际上根本不是泄漏:

Q6.2 My tool detect memory leaks in application with STLport. Is this leak from STLport?

A6.2 In most cases this are 'pseudo memory leaks' that some tools wrongly supports.

In the default compile of STLport, the node allocator is used to allocate internal memory. The node allocator works by pre-allocating a large chunk of memory and handing out small memory blocks out. The memory chunk is not freed during running an application that uses STLport (i.e. it don't returned to system, There are tools like BoundsChecker, Purify or Valgrind that check for memorytml leaks, for memory that isn't freed when no longer used. These tools may report false memory leaks when one uses STLport's node allocator. The memory chunk is normally freed at application end, but the memory checkers usually report memory leaks before that point. Another memory problem might be reported when you use shared libraries (e.g. DLL, this problem specific for Windows DLL model) that uses STLport internally and are statically link to it. If memory is allocated in a dll and released in an other then the STLport node allocator will keep the released memory for a future use. If you do not use this memory then your application global memory consumtion will grow until the appli crash even if there is no realy memory leak. This is why you should always use a coherent configuration everything in dll or everything in static lib.

There are ways to remove the pseudo memory leaks (since the memory is properly freed at the end of the program, the leaks are just pseudo-ones). You could use another allocator that is used in STLport. Open the file "stlport/stl/_site_config.h" and uncomment either one of the following:

_STLP_USE_NEWALLOC   enables a simple allocator that uses "new/delete"
_STLP_USE_MALLOC     enables a simple allocator that uses "malloc/free"

The new/delete allocator has the advantage of giving an entry point to track memory starvation, see set_new_handler in your compiler doc or the C++ Standard for more information.

Alternatively you can define the following symbol, just uncomment it in "stlport/stl/_site_config.h".

_STLP_LEAKS_PEDANTIC

The symbol forces freeing all memory chunks. Also see the comments around the symbol in the config file.

Note that you have to recompile STLport AND your application and all of your dependent libraries if you make any change to the file!

There are also some defines that help in debugging memory problems in STLport. In _STLP_DEBUG mode, just also define the following symbols, either in "./stlport/stl_user_config.h" or in your project settings:

_STLP_DEBUG_ALLOC
_STLP_DEBUG_UNINITIALIZED        

You don't need to rebuild STLport for these options, but you have to rebuild your application and all of your dependent libraries if you make any change to the file.

也就是说,在早期的 C++Builder 版本中使用的 RogueWave STL 也随 C++Builder 6 一起提供,以便与旧代码向后兼容,并且不会遇到此问题。您可以通过在项目的条件列表中定义 _USE_OLD_RW_STL 从 STLPort 切换到 RogueWave。