У меня есть простая модель ActiveRecord под названием Student
со 100 записями в таблице. В сеансе консоли rails я делаю следующее:
ObjectSpace.each_object(ActiveRecord::Base).count
# => 0
x = Student.all
ObjectSpace.each_object(ActiveRecord::Base).count
# => 100
x = nil
GC.start
ObjectSpace.each_object(ActiveRecord::Base).count
# => 0 # Good!
Теперь я делаю следующее:
ObjectSpace.each_object(ActiveRecord::Base).count
# => 0
x = Student.all.group_by(&:last_name)
ObjectSpace.each_object(ActiveRecord::Base).count
# => 100
x = nil
GC.start
ObjectSpace.each_object(ActiveRecord::Base).count
# => 100 # Bad!
Может ли кто-нибудь объяснить, почему это происходит, и есть ли разумный способ решить эту проблему, не зная основы хэш-структуры? Я знаю, что могу это сделать:
x.keys.each{|k| x[k]=nil}
x = nil
GC.start
и он удалит все объекты Student из памяти правильно, но мне интересно, существует ли общее решение (моя реальная проблема широко распространена и имеет более сложные структуры данных, чем хэш, показанный выше).
Я использую Ruby 1.9.3-p0 и Rails 3.1.0.
ОБНОВЛЕНИЕ (РЕШЕНО)
В соответствии с приведенным ниже описанием Оскара Дель Бена в объектном фрагменте кода создается несколько объектов ActiveRecord:: Relation (они фактически созданы в обоих фрагментах кода, но по какой-то причине они "плохо себя ведут" только во втором. пролить свет на почему?). Они поддерживают ссылки на объекты ActiveRecord через переменную экземпляра, называемую @records. Эта переменная экземпляра может быть установлена равной нулю через метод "reset" в ActiveRecord:: Relation. Вы должны выполнить это для всех объектов отношений:
ObjectSpace.each_object(ActiveRecord::Base).count
# => 100
ObjectSpace.each_object(ActiveRecord::Relation).each(&:reset)
GC.start
ObjectSpace.each_object(ActiveRecord::Base).count
# => 0
Примечание. Вы также можете использовать Mass.detach(используя ruby-mass драгоценный камень Oscar Del Ben), хотя он будет намного медленнее, чем код выше. Обратите внимание, что приведенный выше код не удаляет из памяти несколько объектов ActiveRecord:: Relation. Однако они кажутся довольно незначительными. Вы можете попробовать:
Mass.index(ActiveRecord::Relation)["ActiveRecord::Relation"].each{|x| Mass.detach Mass[x]}
GC.start
И это приведет к удалению некоторых объектов ActiveRecord:: Relation, но не всех из них (не знаю, почему, а те, которые остались, не имеют Mass.references. Weird).