Коллекция Garbarge в Ruby с ссылками на Circular Object

У меня возникла проблема с сборкой мусора в 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

Сделайте некоторые вещи, которые делают объекты, и найдите соответствующий идентификатор объекта. GC.start, то:

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

Похоже, здесь есть круговой эталонный шаблон, но он полностью содержится в этих четырех объектах, поэтому коллекционер Mark-and-Sweep должен найти их и удалить их.

Итак, либо есть ошибка в моей find_dependencies_function, Mass gem, либо сборщике мусора Ruby. Как я сужу это, чтобы выяснить, в чем проблема и решить эту утечку памяти?

Ответ 1

GC в Ruby работает по существу так:

  • Отметьте все глобальные объекты как живые.

  • Прокрутка объектов, сбор мусора, если родитель жив.

Итак, в случае циклической ссылки A, удерживающая на B, удерживающую A, получит GC'd, потому что ни один из них не удерживается живым объектом.

В комментариях что-то обязательно держится на объекте где-то... Или, может быть, 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