【问题标题】:How to measure Memory Usage of std::unordered_map如何测量 std::unordered_map 的内存使用情况
【发布时间】:2014-08-19 03:17:16
【问题描述】:

我们知道像 std::unordered_map use a lot memory 这样的基于哈希表的容器实现,但我不知道多少是多少?

除了空间复杂度符号,不考虑容器元素是否是指向更大对象的指针:

有什么方法可以计算出这样的容器在运行时使用了多少字节

有没有办法在运行时告诉任何容器使用了多少内存?

【问题讨论】:

  • 有趣的问题,但听起来非常具体。
  • Valgrind 或自定义分配器可能会起作用。
  • @user657267 一个参考或如何会很好。
  • 多少多少??

标签: c++ unordered-map


【解决方案1】:

没有可移植的方法来判断正在使用的字节数。你能发现的是:

  • size() 表示容器中插入了多少数据元素
  • bucket_count() 表示底层哈希表有多少个桶,每个桶都可以托管一个指向相关元素的链表

现在:

  • 实际用于元素存储的字节为m.size() * sizeof(M::value_type)

  • 用于哈希表存储桶的字节取决于内部列表的存储方式 - std::unordered_map::bucket_size 具有恒定的复杂性,因此我们可以合理地猜测每个存储桶将有一个 size() 和头指针,所以m.bucket_count() * (sizeof(size_t) + sizeof(void*)) 是一个合理的猜测,尽管由于load_factor() 是有界的并且每个桶没有存储size,因此可能只有恒定的摊销复杂性(我更喜欢以这种方式实现它我自己)

  • 如果每个插入的元素都是列表的一部分,它们将需要一个 next 指针,因此我们可以添加另一个 m.size() * sizeof(void*)

  • 每个内存分配可以向上舍入到便于内存分配库管理的大小 - 例如2 的下一个幂,接近 100% 最坏情况下的低效率和 50% 平均值,所以让我们为列表节点添加 50%,因为桶可能是给定 size_t 和指针的 2 的幂:50% * @987654332 @

  • 尤其是在调试模式下,可能存在任意数量的特定于实现的内务管理和错误检测数据

您可以通过创建多个大表并查看 top 或 Process Manager 如何报告不同的内存使用情况来进一步探索这一点。

【讨论】:

    【解决方案2】:

    如果你想得到一个粗略的大小,我认为bucket_count()max_load_factor() 就足够了,它给出了当前的桶数和负载因子。

    理性:

    • 如果load_factor bucket_count() >= map 中的item,那么bucket_count()就是内存使用的大小。

    • 如果load_factor > 1,则bucket_count() * load_factor 表示地图中的最大项目。请注意,这是最大尺寸,而不是实际尺寸。

    因此,粗略的内存使用情况可能如下所示:

      unsigned n = mymap.bucket_count();
      float m = mymap.max_load_factor();
      if (m > 1.0) {
        return n * m;
      }
      else {
        return n;
      }
    

    如果你想得到准确的内存使用情况,你可能需要统计所有的桶,看看里面有多少元素:

      size_t count = 0;
      for (unsigned i = 0; i < mymap.bucket_count(); ++i) {
        size_t bucket_size = mymap.bucket_size(i);
        if (bucket_size == 0) {
          count++;
        }
        else {
          count += bucket_size;
        }
      }
    

    【讨论】:

    • 默认情况下,unordered_map 容器的 max_load_factor 为 1.0。每当其load factor 在操作中超过其max_load_factor 时,容器会自动执行重新哈希。link
    • bucket_size() 不是只返回这个桶中元素的数量吗?因此,您只需要获取容器的 size() ,然后在每个未使用的存储桶中增加一次。
    最近更新 更多