我遇到一个奇怪的问题,我正在使用的 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 被关闭引起的。我认为之前请求的对象仍在对象空间中,但我不确定如何删除它。
最佳答案
这很容易用 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
指的是新类,而不是旧类。
关于ruby-on-rails - 在对象空间 object_id 中复制类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9592192/