计算地图的内存占用量(或字节长度)

huangapple go评论122阅读模式
英文:

Computing the memory footprint (or byte length) of a map

问题

我想将一个地图限制为最大X字节。然而,似乎没有直接计算地图字节长度的方法。

"encoding/binary"包有一个很好的Size函数,但它只适用于切片或"固定值",而不适用于地图。

我可以尝试从地图中获取所有键/值对,推断它们的类型(如果是map[string]interface{}),然后计算长度 - 但这既麻烦又可能不正确(因为这将排除地图本身的"内部"Go成本 - 管理指向元素的指针等)。

有没有建议的方法来做到这一点?最好有一个代码示例。

英文:

I want to limit a map to be maximum X bytes. It seems there is no straightforward way of computing the byte length of a map though.

"encoding/binary" package has a nice Size function, but it only works for slices or "fixed values", not for maps.

I could try to get all key/value pairs from the map, infer their type (if it's a map[string]interface{}) and compute the length - but that would be both cumbersome and probably incorrect (because that would exclude the "internal" Go cost of the map itself - managing pointers to elements etc).

Any suggested way of doing this? Preferably a code example.

答案1

得分: 11

这是一个地图头的定义:

  1. // 一个 Go 地图的头部。
  2. type hmap struct {
  3. // 注意:Hmap 的格式已经编码在 ../../cmd/gc/reflect.c 和 ../reflect/type.go 中。
  4. // 不要在不修改那些代码的情况下更改此结构!
  5. count int // 存活单元格的数量 == 地图的大小。必须是第一个字段(由 len() 内建函数使用)
  6. flags uint32
  7. hash0 uint32 // 哈希种子
  8. B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
  9. buckets unsafe.Pointer // 2^B 个桶的数组。如果 count==0,则可能为 nil。
  10. oldbuckets unsafe.Pointer // 之前的桶数组,大小为当前大小的一半,只有在扩容时非 nil
  11. nevacuate uintptr // 疏散的进度计数器(小于此值的桶已经被疏散)
  12. }

计算其大小非常简单(使用 unsafe.Sizeof)。

这是地图指向的每个单独桶的定义:

  1. // Go 地图的一个桶。
  2. type bmap struct {
  3. tophash [bucketCnt]uint8
  4. // 后面跟着 bucketCnt 个键,然后是 bucketCnt 个值。
  5. // 注意:将所有键放在一起,然后将所有值放在一起,比交替键/值/键/值/... 的代码稍微复杂一些,但它允许我们消除填充,而对于例如 map[int64]int8,需要填充。
  6. // 后面跟着一个溢出指针。
  7. }

bucketCnt 是一个常量,定义如下:

  1. bucketCnt = 1 << bucketCntBits // 等于十进制 8
  2. bucketCntBits = 3

最终的计算公式为:

  1. unsafe.Sizeof(hmap) + (len(theMap) * 8) + (len(theMap) * 8 * unsafe.Sizeof(x)) + (len(theMap) * 8 * unsafe.Sizeof(y))

其中 theMap 是你的地图值,x 是地图的键类型的值,y 是地图的值类型的值。

你需要通过汇编将 hmap 结构与你的包共享,类似于运行时中的 thunk.s

英文:

This is the definition for a map header:

  1. // A header for a Go map.
  2. type hmap struct {
  3. // Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
  4. // ../reflect/type.go. Don&#39;t change this structure without also changing that code!
  5. count int // # live cells == size of map. Must be first (used by len() builtin)
  6. flags uint32
  7. hash0 uint32 // hash seed
  8. B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
  9. buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
  10. oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
  11. nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
  12. }

Calculating its size is pretty straightforward (unsafe.Sizeof).

This is the definition for each individual bucket the map points to:

  1. // A bucket for a Go map.
  2. type bmap struct {
  3. tophash [bucketCnt]uint8
  4. // Followed by bucketCnt keys and then bucketCnt values.
  5. // NOTE: packing all the keys together and then all the values together makes the
  6. // code a bit more complicated than alternating key/value/key/value/... but it allows
  7. // us to eliminate padding which would be needed for, e.g., map[int64]int8.
  8. // Followed by an overflow pointer.
  9. }

bucketCnt is a constant defined as:

  1. bucketCnt = 1 &lt;&lt; bucketCntBits // equals decimal 8
  2. bucketCntBits = 3

The final calculation would be:

  1. unsafe.Sizeof(hmap) + (len(theMap) * 8) + (len(theMap) * 8 * unsafe.Sizeof(x)) + (len(theMap) * 8 * unsafe.Sizeof(y))

Where theMap is your map value, x is a value of the map's key type and y a value of the map's value type.

You'll have to share the hmap structure with your package via assembly, analogously to thunk.s in the runtime.

huangapple
  • 本文由 发表于 2015年8月6日 13:34:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/31847549.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定