计算无序映射占用的内存空间

时间:2014-03-19 07:11:07

标签: c++ memory-management unordered-map

我有两个无序的地图:(代码在linux中执行)

第一张无序地图:

它包含更多至少65536个条目。每个条目都包含

int
unsigned char
unsigned char

第二个无序地图:

它包含少于65536个肠道。每个条目都包含

int
int
int
vector <char>

现在我想根据上面两个无序映射占用的内存(以字节为单位)对两者进行比较。之后我想计算实现的内存压缩。 请指导我如何找到两张无序地图占用的内存?

第二个无序地图的详细信息:

typedef std::tuple<int, int> key_t;

struct KeyHasher
{
  std::size_t operator()(const key_t& k) const
  {
      using boost::hash_value;
      using boost::hash_combine;

      // Start with a hash value of 0    .
      std::size_t seed = 0;

      // Modify 'seed' by XORing and bit-shifting in
      // one member of 'Key' after the other:
      hash_combine(seed,hash_value(std::get<0>(k)));
      hash_combine(seed,hash_value(std::get<1>(k)));

      // Return the result.
      return seed;
  }
};

struct Ndata
{
int value;
vector<char> accept ;
};

typedef boost::unordered_map<const key_t,Ndata,KeyHasher> SecondMap;
}

3 个答案:

答案 0 :(得分:2)

我认为,如果不查看STL使用的精确unordered_map实现,我们就不能准确回答您的问题。

但是,基于unordered_map interface,你可以做出正确的教育猜测:

unordered_map需要存储:

  • 一个bucket容器(可能是类似矢量的结构)

  • max_bucket_count桶(可能是单链接列表结构)

  • 每个项目的一个完整条目(不仅是值,还包括处理密钥哈希冲突的密钥)

快速浏览一下Libc ++实现后,还需要存储空间:

  • 散列函数对象

  • 相等测试功能对象

  • 分配器功能对象

考虑到这一点,我的猜测就像:

typedef unordered_map<K, V, ...> tMyMap;

size_t getMemoryUsage(const tMyMap& map) {
  auto entrySize = sizeof(K) + sizeof(V) + sizeof(void*);
  auto bucketSize = sizeof(void*);
  auto adminSize = 3 * sizeof(void*) + sizeof(size_t);

  auto totalSize = adminSize + map.size() * entrySize + map.max_bucket_count() * bucketSize();
  return totalSize;
}

这仅适用于您的第一个案例,因为在第二种情况下,每个条目可以根据每个向量的大小而具有完全不同的内存使用量。对于第二种情况,您必须添加如下内容:

size_t getMemoryUsage(const tMyMap& map) {
  auto entrySize = sizeof(K) + sizeof(V) + sizeof(void*);
  auto bucketSize = sizeof(void*);
  auto adminSize = 3 * sizeof(void*) + sizeof(size_t);
  auto totalSize = adminSize + map.size() * entrySize + map.max_bucket_count() * bucketSize();

  auto contentSize = 0;
  for (const auto& kv : map) {
    // since accept is a vector<char>, 
    // it uses capacity() bytes of additional memory
    contentSize += kv.second.accept.capacity();
  }
  totalSize += contentSize;

  return totalSize;
}

然而,考虑到现实世界的分配逻辑,地图实际使用的内存可能与此有很大不同,原因在于:外部碎片。如果你想100%确定unordered_map使用了多少内存,你还需要考虑分配器行为。

答案 1 :(得分:2)

一种可能的方法是使用自定义分配器通过实验找出。

直接的解决方案可以利用C ++ 11的“Scoped allocator模型”(另请参阅The Scoped Allocator Model (Rev 2)Stroustrup: Scoped allocators。“范围分配器”将应用于容器,将递归< / em>到它的元素。

std::unordered_map及其元素提供这样的自定义分配器将使您能够精确计算块的数量,它的大小和总量。

顺便说一下,作用域分配器还可以让你优化内存消耗和性能,例如通过提供“竞技场分配器”。

只有一点需要注意:尽管C + 11一致性需要Scoped Allocator模型,但很可能它并没有在Compiler供应商提供的标准库中实现。例如,clang的标准库完全实现了所有容器的Scoped分配器。关于海湾合作委员会,请在此处阅读:GCC Status和GCC邮件列表。

修改

完全不同的方法是使用分析内存消耗的工具。例如,Xcode IDE提供了一个出色的工具“Instruments”,它提供了各种分析方法,一种用于跟踪堆和对象分配。只需几秒钟就可以比较两个不同的版本。当然,可用的工具会因您的平台而异;)

答案 2 :(得分:0)

我建议创建一个包含地图的数组。 您将能够创建大量的内容(例如10万)然后您可以将总内存(由操作系统指示)除以1万。您需要考虑开销(分配地图之前的内存消耗)(包括数组)。

执行大量的sizeof无济于事,因为对于堆上的每个分配,您都有实现定义的开销。例如,在Visual Studio 2013中,Release分配由8个字节的多个(或大型数组的16个字节)完成。