2012-03-06 2 views
7

레일즈 엔진의 특정 모델이 오브젝트 공간에서 중복되는 이상한 문제가 있습니다.오브젝트 공간에서 클래스 복제하기

(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

+1이 보이지 않습니다. 같은 상수에 바인딩 된 두 개의 객체가있을 수 있습니까? # {klass.inspect}는 무엇을 "puts"합니까? # {klass.object_id} "if ..."출력은 무엇입니까? –

+0

어떤 종류의 클래스'DynamicFieldsets :: Field'입니까? 그거 어디서 났어? –

+0

DynamicFieldsets :: Field는 레일 엔진에서 오는 ActiveRecord :: Base 객체입니다. 오브젝트 공간에서 클래스를 조사 할 때 오브젝트 ID를 제외하고는 클래스가 동일합니다. is_a와 같이 객체를 검사하는 메소드를 제외하고 is가 동일한 지 확인하는 메소드는 true를 반환합니다. . – jeremiahishere

답변

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. 이 정의 된 경우 어떻게 좋은 :-)

이 쓰레기 수집해야하고 GC.start로 GC를 트리거 할 수 있지만,

당신 주위에 거짓말을 기존 클래스의 인스턴스가있는 경우 (같은 here을 설명 된대로 레일 실제로 DynamicFieldsets::Field.before_remove_const를 호출합니다 내 예에서 first_x) 또는 하위 클래스에서 오래된 클래스를 가비지 수집 할 수 없습니다.

is_a?은 새로운 클래스의 새 인스턴스가 kind_of?is_a?이되므로 제대로 작동해야합니다. 내 예제에서 : X 새로운 클래스가 아닌 기존의 클래스를 참조로

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

이것은 올바른 동작입니다.