在对象空间object_id中复制类

时间:2012-03-06 21:26:15

标签: ruby-on-rails ruby gem rails-engines

我有一个奇怪的问题,我正在使用的rails引擎中的某些模型在对象空间中被复制。

(rdb:1) ObjectSpace.each_object(::Class).each { |klass| puts klass.to_s + ": " + klass.object_id.to_s if klass.to_s.eql?("DynamicFieldsets::Field") }
DynamicFieldsets::Field: 66866100
DynamicFieldsets::Field: 71836380
2479

发生这种情况时,我不能使用is_a?或等式检查以测试对象是Field类的实例。问题只发生在开发中,看起来它可能是由cache_classes关闭引起的。我认为上一个请求中的对象仍然在对象空间中,但我不确定如何删除它。

1 个答案:

答案 0 :(得分:2)

使用remove_const

可以轻松复制
class X
  def self.foo
    "hello"
  end
end
first_x = X.new

Object.send :remove_const, :X
class X
  def self.foo
    "world"
  end
end
second_x = X.new

p first_x.class, first_x.class.object_id, second_x.class, second_x.class.object_id
  # => X, <an_id>, X, <another_id>
p first_x.class.foo, second_x.class.foo
  # => "hello", "world"

正如您所说,只有在开发过程中才会出现此症状。当Rails重新加载类时,它只是在已定义的类上调用remove_const,强制重新加载它们(使用autoload)。 Here's the code。如果已定义,Rails实际上会调用DynamicFieldsets::Field.before_remove_const,如here所述,有多好: - )

这些应该是垃圾收集的,您可以使用GC.start触发GC,但如果您有旧类的实例(例如我的示例中的first_x)或子类,则旧类不能垃圾收集。

请注意,is_a?应该可以正常工作,因为新实例将是新类的kind_of?is_a?。在我的例子中:

first_x.is_a? X  # => false
second_x.is_a? X # => true

这是正确的行为,因为X指的是新类,而不是旧类。