我发现 ruby-prof 在定位内存泄漏方面不是很有用,因为您需要一个修补过的 Ruby 解释器。在 Ruby 2.1 中,跟踪对象分配变得更加容易。或许自己去探索才是最好的选择。
我推荐这篇博文Ruby 2.1:objspace.so http://tmm1.net/ruby21-objspace/作者:tmml,他是 Ruby 核心开发人员之一。基本上,您可以在调试应用程序时获取大量信息:
ObjectSpace.each_object{ |o| ... }
ObjectSpace.count_objects #=> {:TOTAL=>55298, :FREE=>10289, :T_OBJECT=>3371, ...}
require 'objspace'
ObjectSpace.memsize_of(o) #=> 0 /* additional bytes allocated by object */
ObjectSpace.count_tdata_objects #=> {Encoding=>100, Time=>87, RubyVM::Env=>17, ...}
ObjectSpace.count_nodes #=> {:NODE_SCOPE=>2, :NODE_BLOCK=>688, :NODE_IF=>9, ...}
ObjectSpace.reachable_objects_from(o) #=> [referenced, objects, ...]
ObjectSpace.reachable_objects_from_root #=> {"symbols"=>..., "global_tbl"=>...} /* in 2.1 */
使用 Ruby 2.1,您甚至可以开始跟踪新对象的分配并收集有关每个新对象的元数据:
require 'objspace'
ObjectSpace.trace_object_allocations_start
class MyApp
def perform
"foobar"
end
end
o = MyApp.new.perform
ObjectSpace.allocation_sourcefile(o) #=> "example.rb"
ObjectSpace.allocation_sourceline(o) #=> 6
ObjectSpace.allocation_generation(o) #=> 1
ObjectSpace.allocation_class_path(o) #=> "MyApp"
ObjectSpace.allocation_method_id(o) #=> :perform
Use pry https://github.com/pry/pry and 窥探bug https://github.com/deivid-rodriguez/pry-byebug并开始探索您认为可能会增长的内存堆,分别尝试代码中的不同段。在 Ruby 2.1 之前我一直依赖ObjectSpace.count_objects
并计算结果的差异,看看是否有一种对象类型增长特别明显。
当增长的对象数量在迭代期间重新测试回小得多的数量而不是继续增长时,垃圾收集会正常工作。无论如何,垃圾收集器应该一直运行,您可以通过查看垃圾收集器统计。 http://ruby-doc.org/core-2.0.0/GC.html#method-c-stat
根据我的经验,这是字符串或符号(T_STRING
)。符号红宝石 2.2.0 之前 https://www.ruby-lang.org/en/news/2014/12/25/ruby-2-2-0-released/没有被垃圾收集,因此请确保您的 CSV 或其部分内容不会在途中转换为符号。
如果您觉得不舒服,请尝试使用 JRuby 在 JVM 上运行代码。至少 VisualVM 等工具可以更好地支持内存分析。