【问题标题】:Garbarge Collection in Ruby with Circular Object References带有循环对象引用的 Ruby 中的垃圾收集
【发布时间】:2013-03-29 20:29:00
【问题描述】:

我在 Ruby 中遇到垃圾收集问题,我认为应该进行垃圾收集的对象没有被垃圾收集。

require 'ruby-mass'

def find_dependencies(_object_id,_mapped = {})
  mapped = _mapped
  points_to_object = Mass.references(Mass[_object_id])
  ids = points_to_object.keys.map{|x| /\#(\d*)/.match(x).captures.first.to_i}
  mapped[_object_id] = ids

  unmapped = ids - mapped.keys
  unmapped.each do |x|
    new_deps = find_dependencies(x,mapped)
    mapped.merge(new_deps)
  end
  mapped
end

做一些制作对象的事情,并找到相关的对象 ID。 GC.start,然后:

> find_dependencies(144789180)
=> {144789180=>[61895480, 144786340, 147807540],
 61895480=>[144789180],
 144786340=>[144789180],
 147807540=>[144789180]}

看起来这里有一个循环引用模式,但它都完全包含在这四个对象中,所以 Mark-and-Sweep 收集器应该找到它们并删除它们。

所以,要么我的 find_dependencies_function、Mass gem 或 Ruby 的垃圾收集器中存在错误。如何缩小范围以找出问题所在并解决此内存泄漏?

【问题讨论】:

  • Mark-and-sweep 无法处理这类事情。为此,您必须在这些对象中使​​用 Wea​​kRef 以允许收集器移除整棵树。
  • 为什么标记和扫描不能处理这些事情?我可以看到它们会如何通过引用计数,但是这些不应该被标记,应该被收集,不是吗?
  • 我首先要问——你是如何丢失对象引用的?是否绝对没有其他对子对象的引用?
  • @Linuxios 什么? Mark-and-sweep 是处理循环引用的自动内存管理方案的教科书示例(与不做的简单引用计数相反)。您所说的“这些东西”还有什么意思?收集仍然可以到达的对象?嗯,这是真的,但有点弄巧成拙,不收集可达对象是所有 GC 的核心要求。
  • @aaronjg:如果没有看到包含导致问题的对象的可重现代码,我很难说出这里发生了什么。你能把它添加到你的示例代码中吗?

标签: ruby garbage-collection


【解决方案1】:

Ruby 中的 GC 基本上是这样工作的:

  1. 将所有全局对象标记为活动。

  2. 扫描对象,进行垃圾收集,除非父对象处于活动状态。

因此,在循环引用的情况下,A 持有 B 持有 A 将被 GC'd 因为两者都没有被活动对象持有。

根据 cmets,某些东西必然会在某处抓住对象......或者 Mass 正在捕捉 RangeError 或其他东西......

>> a = {}
=> {}
>> a[:a] = a
=> {:a=>{...}}
>> a.object_id
=> 2269556540
>> a = nil
=> nil
>> GC.start
=> nil
>> ObjectSpace._id2ref(2269556540)
RangeError: 0x8746af3c is recycled object
    from (irb):17:in `_id2ref'
    from (irb):17

【讨论】:

    猜你喜欢
    • 2013-05-11
    • 2011-09-27
    • 2011-11-12
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    相关资源
    最近更新 更多