我想创建一个hash,但我只对keys. 因此,我希望内存占用values尽可能小。最适合分配的对象是什么?
nil?- 一个很短的符号,比如
:a? - 更小的东西?
你可以使用任何你想要的值,只要你使用相同的值。
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为简单起见,它用作值。
以下适用于官方的 Ruby 实现。在这方面,其他实现方式可能有所不同。
nil, true,false和Fixnums 在 C 级别的指针内编码,而所有其他对象将涉及一个实际指向某处的指针(因此您将拥有指针的空间消耗加上它指向的空间)。所以这些对象是内存占用最小的对象。
其中,nil在语义上最有意义。