【发布时间】:2014-12-12 14:59:46
【问题描述】:
下面的代码在我的 Debian 机器上引发了一种奇怪的内存行为。 即使在地图被清除后,htop 显示程序仍然使用大量内存,这让我觉得有内存泄漏。奇怪的事实是它只在某些情况下出现。
#include <map>
#include <iostream>
#include <memory>
int main(int argc, char** argv)
{
if (argc != 2)
{
std::cout << "Usage: " << argv[0] << " <1|0> " << std::endl;
std::cout << "1 to insert in the second map and see the problem "
"and 0 to not insert" << std::endl;
return 0;
}
bool insertion = atoi(argv[1]);
std::map<uint64_t, std::shared_ptr<std::string> > mapStd;
std::map<uint64_t, size_t> counterToSize;
size_t dataSize = 1024*1024;
uint64_t counter = 0;
while(counter < 10000)
{
std::shared_ptr<std::string> stringPtr =
std::make_shared<std::string>(dataSize, 'a');
mapStd[counter] = stringPtr;
if (insertion)
{
counterToSize[counter] = dataSize;
}
if (counter > 500)
{
mapStd.erase(mapStd.begin());
}
std::cout << "\rInserted chunk " << counter << std::flush;
counter++;
}
std::cout << std::endl << "Press ENTER to delete the maps" << std::endl;
char a;
std::cin.get(a); // wait for ENTER to be pressed
mapStd.clear(); // clear both maps
counterToSize.clear();
std::cout << "Press ENTER to exit the program" << std::endl;
std::cin.get(a); // wait for ENTER to be pressed
return 0;
}
说明:
代码在堆栈上创建了两个映射(但如果它们是在堆上创建的,问题是相同的)。然后它将字符串的 std::shared_ptr 插入到第一个映射中。每个字符串的大小为 1MB。一旦插入了 500 个字符串,每个新插入的字符串都会删除第一个,因此映射使用的总内存始终等于 500MB。当总共插入了 10000 个字符串时,程序等待用户按 ENTER。如果您启动程序并将 1 作为第一个参数传递,那么对于第一个映射中的每个插入,也会对第二个映射进行另一个插入。如果第一个参数为 0,则不使用第二个映射。第一次按下 ENTER 后,两个地图都将被清除。程序仍在运行并再次等待按 ENTER,然后退出。
事实如下:
-
1234563 ), htop 表示程序 STILL USE 500MB OF MEMORY!!如果程序以 0 作为第一个参数启动,则内存被正确释放。
本机使用 g++4.7.2 和 libstdc++.so.6.0.17。我试过 g++4.8.2 和 libstdc++.so.6.0.18,同样的问题。
- 我在 64 位 Fedora 21 上尝试过 g++4.9.2 和 libstdc++.so.6.0.20,同样的问题。
- 我已经在带有 g++4.8.2 和 libstdc++.so.6.0.19 的 32 位 Ubuntu 14.04 上尝试过,问题没有出现!
- 我在 32 位 Debian 3.2.54-2 上使用 g++4.7.2 和 libstdc++.so.6.0.17 进行了尝试,没有出现问题!
- 我在 64 位 Windows 上试过,问题没有出现!
- 在存在问题的机器上,如果您反转清除地图的行(因此,如果您先清除 uint64_t、size_t 地图,问题就会消失!
有人对这一切有解释吗???
【问题讨论】:
-
内存分配器由C++标准库实现,与gcc一起使用libc的
malloc。您还应该包括您在每台测试机器上使用的 libc 版本。 Windows,取决于编译器,可能有自己完全独立的实现。
标签: linux c++11 memory-leaks 64-bit gcc4.7