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好きなものを指定できます。値は、へのポインタ、またはイミディエート値(、、、または)の場合は値自体xのみを保持します。xniltruefalseFixnum

どちらの場合も、使用されるメモリは同じです。プラットフォーム上のポインタのサイズ(つまり0.sizeバイト)になります。Cコードでは、これはに対応しVALUEます。

同じオブジェクト(つまり同じ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、確実な方法は、、、、、またはを使用することです。はどこでも同じであり、文字列は1回だけ保存され、コード内のすべてのシンボルで共有されます。truenilFixnumSymbol: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、キーにのみ使用します。true簡単にするために、値として使用します。

于 2013-02-06T18:47:58.650 に答える
2

以下は、公式の Ruby 実装に適用されます。他の実装では、この点が異なる場合があります。

niltruefalseおよびFixnums は、C レベルでポインター内にエンコードされますが、他のすべてのオブジェクトには、実際にどこかを指すポインターが含まれます (そのため、ポインターのスペース消費とポインターが指すスペースが加算されます)。したがって、これらのオブジェクトはメモリ フットプリントが最も小さいオブジェクトです。

これらのうち、nil意味的に最も理にかなっています。

于 2013-02-06T18:24:58.030 に答える