Ruby Symbol # to_proc пропускает ссылки в 1.9.2-p180? - PullRequest
5 голосов
/ 01 сентября 2011

Хорошо, это моя вторая попытка отладки проблем с памятью в моем приложении Sinatra. Я полагаю, что на этот раз я привел его в простой пример кода.

Кажется, когда я фильтрую массив через .map(&:some_method), это приводит к тому, что элементы в этом массиве не собирают мусор. Выполнение эквивалента .map{|x| x.some_method} вполне нормально.

Демонстрация: дан простой пример класса:

class C
  def foo
    "foo"
  end
end

Если я запускаю следующее в IRB, оно обычно собирается:

ruby-1.9.2-p180 :001 > a = 10.times.map{C.new}
 => [...]
ruby-1.9.2-p180 :002 > b = a.map{|x| x.foo}
 => ["foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo"]
ruby-1.9.2-p180 :003 > ObjectSpace.each_object(C){}
 => 10
ruby-1.9.2-p180 :004 > a = nil
 => nil
ruby-1.9.2-p180 :005 > b = nil
 => nil
ruby-1.9.2-p180 :006 > GC.start
 => nil
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(C){}
 => 0

Так что никаких ссылок на C больше не существует. Хорошо. Но вместо map{|x| x.foo} with map(&:foo) (который объявлен как эквивалент), он не собирается:

ruby-1.9.2-p180 :001 > a = 10.times.map{C.new}
 => [...]
ruby-1.9.2-p180 :002 > b = a.map(&:foo)
 => ["foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "foo"]
ruby-1.9.2-p180 :003 > ObjectSpace.each_object(C){}
 => 10
ruby-1.9.2-p180 :004 > a = nil
 => nil
ruby-1.9.2-p180 :005 > b = nil
 => nil
ruby-1.9.2-p180 :006 > GC.start
 => nil
ruby-1.9.2-p180 :007 > ObjectSpace.each_object(C){}
 => 10
ruby-1.9.2-p180 :008 >

Это ошибка в рубине? Я попробую больше версий ruby, чтобы убедиться, но это кажется очевидной проблемой. Кто-нибудь знает, что я делаю не так?

Edit:

Я пробовал это в 1.8.7-p352, и это не имеет проблемы. 1.9.3-preview1 имеет , но проблема остается. Отчет об ошибке в порядке или я что-то не так делаю?

Edit2: форматирование (почему четыре строки перед каждой строкой дают подсветку синтаксиса, а теги <pre> нет?)

1 Ответ

3 голосов
/ 01 сентября 2011

Поскольку a.map(&:foo) должно быть точным эквивалентом a.map{|x| x.foo}, похоже, вы действительно столкнулись с ошибкой в ​​коде Ruby здесь.Не повредит подать отчет об ошибке на (http://redmine.ruby -lang.org /), самое худшее, что может случиться, - это игнорирование.Вы можете уменьшить вероятность этого, предоставив патч для этой проблемы.

РЕДАКТИРОВАТЬ: Я включил IRB и попробовал ваш код.Я могу воспроизвести проблему, которую вы описываете на ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux].Тем не менее, явный вызов to_proc на символе не страдает от той же проблемы:

irb(main):001:0> class C; def foo; end; end
=> nil
irb(main):002:0> a = 10.times.map { C.new }
=> [...]
irb(main):004:0> b = a.map(&:foo.to_proc)
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
irb(main):005:0> ObjectSpace.each_object(C){}
=> 10
irb(main):006:0> a = b = nil
=> nil
irb(main):007:0> GC.start
=> nil
irb(main):008:0> ObjectSpace.each_object(C){}
=> 0

Кажется, здесь мы сталкиваемся с проблемой неявного преобразования Symbol -> Proc.Возможно, позже я попытаюсь немного погрузиться в источник Ruby.Если это так, я буду держать вас в курсе.

РЕДАКТИРОВАТЬ 2:

Простой способ решения проблемы:

class Symbol
  def to_proc
    lambda { |x| x.send(self) }
  end
end

class C
  def foo; "foo"; end
end

a = 10.times.map { C.new }
b = a.map(&:foo)
p b
a = b = nil
GC.start
p ObjectSpace.each_object(C) {}

печать 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...