Hier ist das NewView
Objekt in einem Referenzzyklus beteiligt, und die Objekte in diesem Zyklus werden nicht automatisch als Teil von CPythons primärem Referenzzählungs-basierten Objekt-Deallokationsmechanismus erfasst. Sie sollten jedoch als Teil von CPythons zyklischem Garbage Collector gesammelt werden, oder Sie können diese Sammlung erzwingen, indem Sie eine gc.collect()
ausführen, so dass es hier keinen tatsächlichen Langzeitspeicherverlust geben sollte.
Ironischer, die eventuelle Übergabe zu erfassen versuchen durch Zugabe einer __del__
Methode NewView
behindert den Prozess, da es das Objekt NewView
uncollectable rendert: zumindest in Python 2, Python wird nicht versuchen Zyklen zu sammeln Objekte enthalten, die __del__
haben Methoden. Details finden Sie unter gc
docs. (Python 3 ist hier etwas cleverer, dank der Änderungen, die in PEP 442 beschrieben sind.) Mit der Methode __del__
, die Python 2 verwendet, wird es im Laufe der Zeit tatsächlich einen langsamen Speicherverlust geben. Die Lösung besteht darin, die __del__
Methode zu entfernen.
Hier ist ein Diagramm, das den Referenzzyklus zeigt (tatsächlich zeigt dies die gesamte stark verbundene Komponente des Objektgraphen mit dem NewView
Objekt): Knoten sind die beteiligten Objekte, und Pfeile gehen von Referrern zu Referenten. Im rechten unteren Teil des Diagramms sehen Sie, dass das Objekt NewView
einen Verweis auf seine oberste Ebene Group
(über das Attribut content
) hat und dass das Objekt Group
einen Verweis zurück auf die ursprüngliche Ansicht hat (das Attribut container
). Es gibt ähnliche Zyklen, die anderswo in der Ansicht stattfinden.
Es ist wahrscheinlich lohnt sich ein Feature-Request auf dem Traits UI-Tracker öffnen: in der Theorie sollte es möglich sein, die Referenzzyklen manuell zu brechen, wenn der Blick nicht mehr benötigt wird, obwohl in der Praxis, die erhebliche erfordern könnten Überarbeitung der Traits UI-Quelle.
Hier einige Code, dass (mit den __del__
Methoden entfernt) zeigt ein Aufruf an gc.collect
das NewView
Objekt sammelt: es speichert einen schwachen Verweis auf die Ansicht auf das A
Beispiel mit einem Rückruf, der meldet, wenn diese Ansicht Müll gesammelt.
from traits.api import HasTraits, Int, Instance
from traitsui.api import View
import gc
import weakref
class NewView(View):
pass
def report_collection(ref):
print("NewView object has been collected")
class A(HasTraits):
a = Int
def default_traits_view(self):
new_view = NewView('a')
self.view_ref = weakref.ref(new_view, report_collection)
return new_view
def open_view():
a = A()
a.configure_traits()
print("Collecting cyclic garbage")
gc.collect()
print("Cyclic garbage collection complete")
Auf meinem Rechner ist hier, was ich sehe, wenn open_view
genannt wird:
>>> open_view()
Collecting cyclic garbage
NewView object has been collected
Cyclic garbage collection complete
Gute Frage, Yves, mit dem Leck scheinbar durch ein paar schnelle Experimentieren mit einem 'weakref' zu' new_view' bestätigt . Meine erste (sehr vorläufige) Vermutung ist, dass Views leicht sind und sich nicht proliferieren lassen, was nicht als ein signifikantes Problem angesehen wurde. Meine zweite Vermutung ist, dass es versteckte Magie gibt. :) Ich habe einige TraitsUI-Assistenten um eine Erklärung gebeten. Wenn wir keine Antwort erhalten, würde ich vorschlagen, sie als TraitsUI-Problem zu veröffentlichen, wo sie im Laufe der Zeit sichtbar bleibt. –