次のスニペットを検討してください。
l = []
while 1
l << 'a random 369-characterish string'
end
^C
# ran this for maybe 4 seconds, and it had 27 million entries in l. memory
# usage was 1.6 GB.
l = nil
# no change in memory usage
GC.start
# memory usage drops a relatively small amount, from 1.6 GB to 1.39 GB.
私は何百万もの要素をRubyのデータ構造に/を通じて押し込んでおり、深刻なメモリの問題を抱えています. この例は、現存するオブジェクトへの参照がない場合でも、Ruby は を明示的に呼び出した後でも [ほとんど] を手放さないことを示していGC.start
ます。
私が実生活で使用しているオブジェクトは、合計で数百万の要素をハッシュにプッシュしますが、ハッシュは一時的なルックアップ テーブルとして使用され、ループが完了するとゼロになります。ただし、このルックアップ テーブルからのメモリは決して解放されないようです。GC にはサイクルごとに分析する必要のある何百万もの無効なオブジェクトがあるため、アプリケーションの速度が非常に遅くなります。私はsparsehash
gemで回避策に取り組んでいますが、これはRubyランタイムがそのように窒息するような手に負えない問題ではないようです。参照は明確に削除され、オブジェクトは明確に収集および廃棄されるべきです。なぜこれが起こっていないのかを理解するのを手伝ってくれる人はいますか?
freenode の #ruby でユーザーの提案を試してみl.delete_if { |x| true}
ましたが、これは非常に遅く、メモリのかなりの解放を引き起こすこともありませんでした。
を使用してruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
います。
編集:
比較のために、ここで実行しpython3
ます:
l = []
while 1:
l.append('a random 369-characterish string')
^C
# 31,216,082 elements; 246M memory usage.
l = []
# memory usage drops to 8K (0% of system total)
python2 でのテストでは、ほぼ同じ結果が表示されます。
これが MRI の実装上の欠陥であると考えるのに十分なのか、それとも GC へのさまざまなアプローチのせいなのかはわかりません。いずれにせよ、Python は、合計で数百万の要素をデータ構造にプッシュし、定期的に構造をゼロにする (一時的なルックアップ テーブルの場合のように) ユース ケースにより適しているようです。
これは単純なものであるべきだと本当に思われます。:\