std::unordered_map 非常高的内存使用率

Posted

技术标签:

【中文标题】std::unordered_map 非常高的内存使用率【英文标题】:std::unordered_map very high memory usage 【发布时间】:2012-02-21 09:56:46 【问题描述】:

昨天我尝试使用std::unordered_map,这段代码让我困惑了它使用了多少内存。

typedef list<string> entityId_list;
struct tile_content 
   char cost;
   entityId_list entities;
;
unordered_map<int, tile_content> hash_map;

for (size_t i = 0; i < 19200; i++) 
   tile_content t;
   t.cost = 1;
   map[i] = t;

所有这部分代码都是在 MS VS2010 中以调试模式编译的。 我在任务管理器中看到的是大约 1200 kb 的“干净”进程,但在填充 hash_map 后,它使用了 8124 kb 的内存。这是unordered_map 的正常行为吗?为什么要使用这么多内存?

【问题讨论】:

只是想注意,即使内部没有存储任何项目(当您通过迭代器擦除时,因为如果映射重新散列迭代器变得无效),无序映射也可以容纳数百兆字节,请参阅此错误报告(这也可能不会影响微软的实施):svn.boost.org/trac/boost/ticket/11419 【参考方案1】:

unordered_map 结构旨在以一种使添加、删除、查找和无序遍历高效的方式保存大量对象。它并不意味着对小型数据结构具有内存效率。为了避免与调整大小相关的惩罚,它在首次创建时分配了许多哈希链头。

【讨论】:

【参考方案2】:

对于大约 20k 个对象,这大约是 6MB,因此每个对象 300 个字节。考虑到哈希表的大小可能会比当前条目多几倍,每个桶本身可能是一个指向冲突对象列表或向量的指针,所有涉及的每个堆分配可能已经四舍五入到最接近的2 的幂,并且您已经进行了调试,这可能会产生一些额外的膨胀,这对我来说听起来都是正确的。

无论如何,您不会对调试版本中任何内容的内存或 CPU 效率感到同情;-P。微软可以在其中注入任何他们喜欢的垃圾,用户对性能没有任何期望。如果您发现优化的构建不好,那么您有话要说。

更一般地说,它如何与size() 缩放非常重要,但完全有理由想知道一个程序如何处理大量相对较小的无序地图。值得注意的是,低于一定的size() 甚至在向量中进行暴力搜索、在排序向量中进行二分搜索或二叉树可能会胜过无序映射,并且内存效率更高。

【讨论】:

你能给出最后一句话的理由吗? @Andrew:有序向量的主要性能优势是连续的内存使用和就地值,而unordered_map 实现倾向于动态分配不同的节点,并且在操作期间必须遵循指向它们的指针;二叉树和排序向量中的操作都涉及 O(log2N) '&lt;' 比较,而 unordered_map operations require a hash function call (which can be expensive but is only done once per operation, and can be orchestrated to happen once per value) and ==` 比较。与往常一样,在您关心时衡量您的实际数据和使用情况。【参考方案3】:

这并不一定意味着哈希映射使用了这么多内存,而是该进程向操作系统请求了这么多内存。

然后,此内存用于满足程序的 malloc/new 请求。一些(或大多数,我不确定)内​​存分配器需要来自操作系统的内存比当时需要更多的内存来提高效率。

要知道 unordered_map 使用了多少内存,我会使用像 perftools 这样的内存分析器。

【讨论】:

以上是关于std::unordered_map 非常高的内存使用率的主要内容,如果未能解决你的问题,请参考以下文章

std::unordered_map::reserve 是不是保证只要映射中的元素较少就不会发生内存分配?

std::unordered_map::clear() 做啥?

两个 std::unordered_map 的交集

std::hash 特化仍未被 std::unordered_map 使用

为啥我不能增加 std::unordered_map 迭代器?

在 std::map 和 std::unordered_map 之间进行选择 [重复]