我想创建一个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
则值本身。x
nil
true
false
Fixnum
无论哪种情况,使用的内存都是一样的!它将是您平台上指针的大小(即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
和Fixnum
s 在 C 级别的指针内编码,而所有其他对象将涉及一个实际指向某处的指针(因此您将拥有指针的空间消耗加上它指向的空间)。所以这些对象是内存占用最小的对象。
其中,nil
在语义上最有意义。