C++ 无序映射析构函数不释放内存?

C++ 无序映射析构函数不释放内存?,c++,stl,heap-memory,C++,Stl,Heap Memory,按照标准,当调用std::unordered_映射的析构函数时(例如,当它离开创建它的作用域时),需要释放它分配的内存。然而,我在多台机器上运行的一个简单实验似乎与此冲突?考虑下面的程序: #include <chrono> #include <iostream> #include <map> #include <unordered_map> #include <memory> #incl

按照标准,当调用std::unordered_映射的析构函数时(例如,当它离开创建它的作用域时),需要释放它分配的内存。然而,我在多台机器上运行的一个简单实验似乎与此冲突?考虑下面的程序:

    #include <chrono>
    #include <iostream>
    #include <map>
    #include <unordered_map>
    #include <memory>
    #include <thread>
    #include <vector>

    void CreateMap() {
        std::unordered_map<int, int> testMap;

        for (int i=0; i < 10000000; i++) {
            testMap[i] = 5;
        }

        std::cout << "finished building map" << std::endl;

        std::this_thread::sleep_for (std::chrono::seconds(15));

        std::cout << "about to exit from CreateMap()" << std::endl;
    }

    int main()
    {
        CreateMap();

        CreateMap(); 

        CreateMap();
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
void CreateMap(){
std::无序图testMap;
对于(int i=0;i<10000000;i++){
testMap[i]=5;
}

std::cout确保
std::unordered_map
不会泄漏。您不能使用系统监视器检查程序是否泄漏,句号。如果有泄漏,您应该查看物理内存使用情况,而不是总内存或虚拟内存。由于页面可以交换到磁盘(pagefile),所以即使物理内存也不能准确反映RAM使用情况即使如此,在OS或C++语言层的优化可能会重用堆内存()来进行优化。涉及的因素太多,而对于检测泄露内存的东西来说,它的价值太大了。查找泄漏的方法是在程序终止时查看堆,例如使用或类似的工具。不用说,避免手动内存管理和使用所有权语义对于避免代码泄漏有很大帮助。

您的测试错误。代码不会泄漏,但释放的内存不一定可供其他程序使用进程(您正在测量的)-它很可能会保留,以便将来由同一进程进行分配

例如,在移除无限循环并降低
i
的限制以适合我的测试沙箱之后,我在Valgrind下运行了代码:

valgrind--泄漏检查=完全。/60112215
==3396096==Memcheck,内存错误检测器
==3396096==2002-2017年版权(C)和GNU GPL'd,朱利安·苏厄德等人。
==3396096==使用Valgrind-3.15.0和LibVEX;使用-h重新运行以获取版权信息
==3396096==命令:./60112215
==3396096== 
竣工图
即将从CreateMap()退出
竣工图
即将从CreateMap()退出
竣工图
即将从CreateMap()退出
==3396096== 
==3396096==堆摘要:
==3396096==在出口处使用:0个块中有0个字节
==3396096==总堆使用率:300044 allocs,300044 frees,13053168字节分配
==3396096== 
==3396096==所有堆块都已释放--不可能存在泄漏
==3396096== 
==3396096==对于检测到的和抑制的错误列表,请使用:-s重新运行
==3396096==错误摘要:来自0个上下文的0个错误(已抑制:来自0的0)
如果您想亲自演示这一点,可以多次调用
CreateMap()
,查看进程的内存使用情况是否没有增加:

int main()
{
    for (auto i = 0;  i < 100;  ++i) {
        CreateMap();
    }
}
intmain()
{
用于(自动i=0;i<100;++i){
CreateMap();
}
}

显然是重新使用了在前一次迭代中释放的内存。

有一个堆管理,它是由编译器的标准(或运行时)库组成的。当内存耗尽时,它试图从OS中获取更多的内存。当内存在C++中释放时,它不一定返回到OS,但通常可以保存在“免费”中。列表以供以后的请求使用。因此,在使用操作系统内存检查工具时,您可能看不到此可用内存。操作系统不必立即释放为您的进程分配的页面,因此在检查内存时仍可以对其进行计数(取决于您检查内存的方式).FYI:今天早上有人问了一个非常类似的问题。你可能有兴趣阅读。@Mathemagician:根据操作系统和分配器的不同,它甚至可以通过向操作系统提供提示来帮助这个过程,例如,在Linux上,它可能
madvise
mmap
ed页面(通常是块大小的一小部分)当没有剩余的分配(如
MADV_DONTNEED
)时,这告诉操作系统它可以删除数据;如果稍后访问页面,操作系统只会根据需要提供填充有零的页面。因此从技术上讲,内存仍然是“分配的”(虚拟地址空间仍在使用,如果需要,可以访问内存),但没有使用物理RAM或交换文件。