7 Stimmen

Duplizieren der Klasse im Objektraum object_id

Ich habe ein seltsames Problem, bei dem bestimmte Modelle in einer Rails-Engine, die ich verwende, im Objektraum dupliziert werden.

(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

Wenn dies geschieht, kann ich keine is_a? oder Gleichheitsprüfungen verwenden, um zu testen, ob ein Objekt eine Instanz der Klasse Field ist. Das Problem tritt nur in der Entwicklung auf, und es sieht so aus, als ob es dadurch verursacht wird, dass cache_classes ausgeschaltet ist. Ich glaube, das Objekt aus der vorherigen Anfrage ist noch im Objektbereich, aber ich bin nicht sicher, wie ich es entfernen kann.

2voto

Marc-André Lafortune Punkte 75645

Dies ist leicht zu reproduzieren mit 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"

Wie Sie sagten, tritt dieses Symptom nur in der Entwicklung auf. Wenn Rails die Klassen neu lädt, ruft es einfach remove_const auf die definierten Klassen, um deren Neuladen zu erzwingen (mit autoload ). Hier ist der Code . Rails wird tatsächlich aufrufen DynamicFieldsets::Field.before_remove_const wenn sie, wie erläutert, definiert ist aquí , wie schön :-)

Diese sollten garbage collected werden und Sie können die GC mit GC.start , aber wenn Sie Instanzen der alten Klassen herumliegen haben (wie first_x in meinem Beispiel), oder Unterklassen, können die alten Klassen nicht garbage collected werden.

Beachten Sie, dass is_a? sollte gut funktionieren, da neue Instanzen in dem Sinne kind_of? y is_a? der neuen Klasse. In meinem Beispiel:

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

Dies ist das richtige Verhalten, denn X bezieht sich auf die neue Klasse, nicht auf die alte Klasse.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X