考虑这个片段:
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 运行时应该像那样窒息。明确删除引用,明确收集和处置对象。谁能帮我弄清楚为什么这没有发生?
我已经尝试过l.delete_if { |x| true}
freenode 上#ruby 中用户的建议,但这确实很慢,而且似乎也从未导致明显的内存释放。
使用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 似乎更适合将总共数百万个元素通过数据结构推送并定期将结构归零的用例(就像临时查找表可能做的那样)。
看起来这确实应该是一个简单的。:\