繁体   English   中英

std::unordered_map 析构函数不释放内存?

[英]std::unordered_map destructor does not free memory?

根据标准,当 std::unordered_map 的析构函数被调用时(例如,当它离开创建它的范围时),人们期望它分配的内存被释放。 然而,我在多台机器上运行的一个简单实验似乎与此冲突? 考虑以下程序:

    #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;
}

在我的机器上,当地图完成构建时会消耗 10% 的 RAM,但我们在 CreateMap() 中最后睡觉。 然而,退出 RAM 后仅下降到 8%(可以玩各种大小的地图以显示地图本身负责超过 2%)所以人们会期望 CreateMap 泄漏内存吗? 然而,对 CreateMap() 的 3 次调用或仅一次调用似乎没有什么区别(因此内存被回收到程序而不是 RAM?)。

这可能是我不理解的关于操作系统内存管理的奇怪之处,即,程序可能会释放内存以供将来使用(未来分配),但不能释放给操作系统(即,用于其他程序中的内存分配) )?

你测试错了。 代码不会泄漏,但释放的内存不一定可用于其他进程(您正在测量的内容) - 它可能会保留为同一进程将来分配的声明。

例如,在删除无限循环并减少i的限制以适合我的测试沙箱后,我在 Valgrind 下运行代码:

valgrind --leak-check=full ./60112215   
==3396096== Memcheck, a memory error detector
==3396096== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3396096== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==3396096== Command: ./60112215
==3396096== 
finished building map
about to exit from CreateMap()
finished building map
about to exit from CreateMap()
finished building map
about to exit from CreateMap()
==3396096== 
==3396096== HEAP SUMMARY:
==3396096==     in use at exit: 0 bytes in 0 blocks
==3396096==   total heap usage: 300,044 allocs, 300,044 frees, 13,053,168 bytes allocated
==3396096== 
==3396096== All heap blocks were freed -- no leaks are possible
==3396096== 
==3396096== For lists of detected and suppressed errors, rerun with: -s
==3396096== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

如果您真的想亲自演示这一点,您可以多次调用CreateMap()并查看进程的内存使用量不会增加:

int main()
{
    for (auto i = 0;  i < 100;  ++i) {
        CreateMap();
    }
}

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

确保std::unordered_map不会泄漏。 您不能使用系统监视器来检查您的程序是否泄漏,期间。 如果有的话,您应该查看物理内存使用情况,而不是总数或虚拟内存。 由于页面可以交换到磁盘(页面文件),因此即使物理内存也不能准确反映 RAM 使用情况。 即便如此,例如优化。 OS 或 C++ 语言级别可能会重用堆内存( 如注释中所述)进行优化。 涉及的因素太多,对于检测泄漏内存这样微妙的事情来说,它的总价值太大了。 查找泄漏的一种简单(通常也是有效的)方法是在程序终止时查看堆,例如。 使用_CrtSetDbgFlag或类似工具。 不用说,避免手动内存管理和使用所有权语义在避免代码泄漏方面大有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM