2

我想创建一个hash,但我只对keys. 因此,我希望内存占用values尽可能小。最适合分配的对象是什么?

  • nil?
  • 一个很短的符号,比如:a?
  • 更小的东西?
4

2 回答 2

5

你可以使用任何你想要的值,只要你使用相同的值。

x = "A string value"
h =  Hash[ 10000.times.map{|i| [i, x]} ]
h2 = Hash[ 10000.times.map{|i| [i, nil]} ]
# h takes the same memory as h2

在上面的例子中,x可以是任何你喜欢的。这些值将只保存指向 的指针,或者如果是立即值(、或 a )x则值本身。xniltruefalseFixnum

无论哪种情况,使用的内存都是一样的!它将是您平台上指针的大小(即0.size字节)。在 C 代码中,这对应于VALUE.

只是要小心重用同一个对象(即 same object_id),而不是每次都创建一个新对象。例如:

h3 =  Hash[ 10000.times.map{|i| [i, "A string value"]} ]
# => h3 will take a lot more space!
h.values.map(&:object_id).uniq.size  # => 1
h3.values.map(&:object_id).uniq.size # => 10000

简而言之,万无一失的方法是使用false, true, nil, aFixnum或 a Symbol,因为符号存储在全局表中。:hello.object_id在任何地方都相同,并且该字符串'hello'仅存储一次并为:hello代码中的所有符号共享。

h4 =  Hash[ 10000.times.map{|i| [i, :some_symbol]} ]
# => h4 will only take as much space as h and h2
h4.values.map(&:object_id).uniq.size # => 1

仅供参考,内置库Set具有相同的要求,即它Hash仅将 a 用于键。true为简单起见,它用作值。

于 2013-02-06T18:47:58.650 回答
2

以下适用于官方的 Ruby 实现。在这方面,其他实现方式可能有所不同。

nil, true,falseFixnums 在 C 级别的指针内编码,而所有其他对象将涉及一个实际指向某处的指针(因此您将拥有指针的空间消耗加上它指向的空间)。所以这些对象是内存占用最小的对象。

其中,nil在语义上最有意义。

于 2013-02-06T18:24:58.030 回答