Objektlebenszyklus¶
Dieser Abschnitt erklärt, wie die Slots eines Typs während des Lebens eines Objekts miteinander in Beziehung stehen. Er ist nicht als vollständiges kanonisches Nachschlagewerk für die Slots gedacht; stattdessen finden Sie detailspezifische Informationen zu einem bestimmten Slot in der Slot-spezifischen Dokumentation unter Typobjektstrukturen.
Lebensereignisse¶
Die folgende Abbildung veranschaulicht die Reihenfolge der Ereignisse, die während des Lebens eines Objekts auftreten können. Ein Pfeil von A nach B zeigt an, dass Ereignis B nach dem Eintreten von Ereignis A auftreten kann, wobei die Beschriftung des Pfeils die Bedingung angibt, die erfüllt sein muss, damit B nach A auftreten kann.
Erläuterung
Wenn ein neues Objekt durch Aufrufen seines Typs konstruiert wird
tp_newwird aufgerufen, um ein neues Objekt zu erstellen.tp_allocwird direkt vontp_newaufgerufen, um den Speicher für das neue Objekt zuzuweisen.tp_initinitialisiert das neu erstellte Objekt.tp_initkann bei Bedarf erneut aufgerufen werden, um ein Objekt neu zu initialisieren. Der Aufruf vontp_initkann auch komplett übersprungen werden, zum Beispiel durch den Aufruf von__new__()durch Python-Code.
Nach Abschluss von
tp_initist das Objekt einsatzbereit.Einige Zeit nach der Entfernung der letzten Referenz auf ein Objekt
Wenn ein Objekt nicht als finalisiert markiert ist, kann es durch Markierung als finalisiert und durch Aufruf seiner
tp_finalize-Funktion finalisiert werden. Python finalisiert ein Objekt *nicht*, wenn die letzte Referenz darauf gelöscht wird; verwenden SiePyObject_CallFinalizerFromDealloc(), um sicherzustellen, dasstp_finalizeimmer aufgerufen wird.Wenn das Objekt als finalisiert markiert ist, kann
tp_clearvom Garbage Collector aufgerufen werden, um von dem Objekt gehaltene Referenzen zu löschen. Es wird *nicht* aufgerufen, wenn die Referenzanzahl des Objekts Null erreicht.tp_deallocwird aufgerufen, um das Objekt zu zerstören. Um Code-Duplizierung zu vermeiden, rufttp_dealloctypischerweisetp_clearauf, um die Referenzen des Objekts freizugeben.Wenn
tp_deallocdie Objektzerstörung abschließt, ruft es direkttp_freeauf (normalerweise gesetzt aufPyObject_Free()oderPyObject_GC_Del(), je nach Typ), um den Speicher freizugeben.
Die Funktion
tp_finalizedarf nach Belieben eine Referenz auf das Objekt hinzufügen. Wenn dies geschieht, wird das Objekt wiederbelebt, was seine bevorstehende Zerstörung verhindert. (Nurtp_finalizedarf ein Objekt wiederbeleben;tp_clearundtp_deallockönnen dies nicht tun, ohnetp_finalizeaufzurufen.) Ob das Wiederbeleben eines Objekts die finalisierte Markierung des Objekts entfernt oder nicht, ist nicht garantiert. Derzeit entfernt Python die finalisierte Markierung nicht von einem wiederbelebten Objekt, wenn es Garbage Collection unterstützt (d. h. das FlagPy_TPFLAGS_HAVE_GCist gesetzt), entfernt die Markierung aber, wenn das Objekt keine Garbage Collection unterstützt; eines oder beide dieser Verhaltensweisen können sich in Zukunft ändern.tp_deallockann optionaltp_finalizeüberPyObject_CallFinalizerFromDealloc()aufrufen, wenn es diesen Code zur Unterstützung der Objektzerstörung wiederverwenden möchte. Dies wird empfohlen, da es garantiert, dasstp_finalizevor der Zerstörung immer aufgerufen wird. Siehe die Dokumentation zutp_deallocfür Beispielcode.Wenn das Objekt Mitglied eines zyklischen Isolats ist und entweder
tp_clearden Referenzzyklus nicht aufbrechen kann oder das zyklische Isolat nicht erkannt wird (vielleicht wurdegc.disable()aufgerufen, oder das FlagPy_TPFLAGS_HAVE_GCwurde in einem der beteiligten Typen fälschlicherweise weggelassen), bleiben die Objekte unendlich lange nicht sammelbar (sie "lecken"). Siehegc.garbage.
Wenn das Objekt als Garbage Collection-unterstützend markiert ist (das Flag Py_TPFLAGS_HAVE_GC ist in tp_flags gesetzt), sind auch die folgenden Ereignisse möglich
Der Garbage Collector ruft gelegentlich
tp_traverseauf, um zyklische Isolate zu identifizieren.Wenn der Garbage Collector ein zyklisches Isolat entdeckt, finalisiert er eines der Objekte in der Gruppe, indem er es als finalisiert markiert und seine
tp_finalize-Funktion aufruft, falls vorhanden. Dies wiederholt sich, bis das zyklische Isolat nicht mehr existiert oder alle Objekte finalisiert wurden.tp_finalizedarf das Objekt wiederbeleben, indem es eine Referenz von außerhalb des zyklischen Isolats hinzufügt. Die neue Referenz bewirkt, dass die Gruppe von Objekten nicht mehr als zyklisches Isolat fungiert (der Referenzzyklus kann noch existieren, aber die Objekte sind dann nicht mehr isoliert).Wenn der Garbage Collector ein zyklisches Isolat entdeckt und alle Objekte in der Gruppe bereits als finalisiert markiert wurden, löscht der Garbage Collector eines oder mehrere der nicht gelöschten Objekte in der Gruppe (möglicherweise gleichzeitig), indem er die
tp_clear-Funktion jedes Objekts aufruft. Dies wiederholt sich, solange das zyklische Isolat noch existiert und nicht alle Objekte gelöscht wurden.
Zerstörung zyklischer Isolate¶
Unten sind die Lebensphasen eines hypothetischen zyklischen Isolats aufgeführt, das bestehen bleibt, nachdem jedes Mitgliedsobjekt finalisiert oder gelöscht wurde. Es handelt sich um ein Speicherleck, wenn ein zyklisches Isolat alle diese Phasen durchläuft; es sollte verschwinden, sobald alle Objekte gelöscht sind, wenn nicht früher. Ein zyklisches Isolat kann entweder verschwinden, weil der Referenzzyklus unterbrochen wird, oder weil die Objekte nicht mehr isoliert sind aufgrund von Finalizer-Wiederbelebung (siehe tp_finalize).
Erreichbar (noch kein zyklisches Isolat): Alle Objekte befinden sich in ihrem normalen, erreichbaren Zustand. Ein Referenzzyklus kann existieren, aber eine externe Referenz bedeutet, dass die Objekte noch nicht isoliert sind.
Unerreichbar, aber konsistent: Die letzte Referenz von außerhalb der zyklischen Objektgruppe wurde entfernt, wodurch die Objekte isoliert wurden (somit ist ein zyklisches Isolat geboren). Keines der Objekte der Gruppe wurde bisher finalisiert oder gelöscht. Das zyklische Isolat verbleibt in diesem Zustand bis zu einem zukünftigen Lauf des Garbage Collectors (nicht unbedingt der nächste Lauf, da der nächste Lauf möglicherweise nicht jedes Objekt scannt).
Gemisch aus finalisierten und nicht finalisierten Objekten: Objekte in einem zyklischen Isolat werden einzeln finalisiert, was bedeutet, dass es eine Zeitspanne gibt, in der das zyklische Isolat aus einer Mischung von finalisierten und nicht finalisierten Objekten besteht. Die Reihenfolge der Finalisierung ist nicht spezifiziert, daher kann sie zufällig erscheinen. Ein finalisiertes Objekt muss sich beim Interagieren mit nicht finalisierten Objekten vernünftig verhalten, und ein nicht finalisiertes Objekt muss die Finalisierung einer beliebigen Teilmenge seiner Referenzobjekte tolerieren können.
Alle finalisiert: Alle Objekte in einem zyklischen Isolat werden finalisiert, bevor eines davon gelöscht wird.
Gemisch aus finalisierten und gelöschten Objekten: Die Objekte können seriell oder gleichzeitig (aber mit gehaltener GIL) gelöscht werden, wobei einige vor anderen fertig werden. Ein finalisiertes Objekt muss die Löschung einer Teilmenge seiner Referenzobjekte tolerieren können. PEP 442 bezeichnet diese Phase als "zyklischen Müll".
Geleakt: Wenn ein zyklisches Isolat weiterhin besteht, nachdem alle Objekte in der Gruppe finalisiert und gelöscht wurden, bleiben die Objekte unendlich lange nicht sammelbar (siehe
gc.garbage). Es ist ein Fehler, wenn ein zyklisches Isolat diese Phase erreicht – es bedeutet, dass dietp_clear-Methoden der beteiligten Objekte den Referenzzyklus nicht wie erforderlich aufgebrochen haben.
Wenn tp_clear nicht existieren würde, hätte Python keine Möglichkeit, einen Referenzzyklus sicher aufzubrechen. Die bloße Zerstörung eines Objekts in einem zyklischen Isolat würde zu einem hängenden Zeiger führen, was zu undefiniertem Verhalten führt, wenn ein Objekt, das auf das zerstörte Objekt verweist, selbst zerstört wird. Der Löschschritt macht die Objektzerstörung zu einem zweistufigen Prozess: zuerst wird tp_clear aufgerufen, um die Objekte teilweise zu zerstören, um sie voneinander zu trennen, und dann wird tp_dealloc aufgerufen, um die Zerstörung abzuschließen.
Im Gegensatz zum Löschen ist die Finalisierung keine Zerstörungsphase. Ein finalisiertes Objekt muss sich weiterhin ordnungsgemäß verhalten und seine Designverträge erfüllen. Der Finalizer eines Objekts darf beliebigen Python-Code ausführen und darf sogar die bevorstehende Zerstörung verhindern, indem er eine Referenz hinzufügt. Der Finalizer ist nur durch die Aufrufsequenz mit der Zerstörung verbunden – wenn er ausgeführt wird, läuft er vor der Zerstörung, die mit tp_clear (falls aufgerufen) beginnt und mit tp_dealloc endet.
Die Finalisierungsphase ist nicht notwendig, um die Objekte in einem zyklischen Isolat sicher wiederherzustellen, aber ihre Existenz erleichtert das Design von Typen, die sich beim Löschen von Objekten vernünftig verhalten. Das Löschen eines Objekts kann es notwendigerweise in einem fehlerhaften, teilweise zerstörten Zustand hinterlassen – es kann unsicher sein, Methoden des gelöschten Objekts aufzurufen oder auf seine Attribute zuzugreifen. Mit der Finalisierung können nur finalisierte Objekte mit gelöschten Objekten interagieren; nicht finalisierte Objekte interagieren garantiert nur mit nicht gelöschten (aber potenziell finalisierten) Objekten.
Zusammenfassend die möglichen Interaktionen
Ein nicht finalisiertes Objekt kann Referenzen auf oder von nicht finalisierten und finalisierten Objekten haben, aber nicht auf oder von gelöschten Objekten.
Ein finalisiertes Objekt kann Referenzen auf oder von nicht finalisierten, finalisierten und gelöschten Objekten haben.
Ein gelöschtes Objekt kann Referenzen auf oder von finalisierten und gelöschten Objekten haben, aber nicht auf oder von nicht finalisierten Objekten.
Ohne Referenzzyklen kann ein Objekt einfach zerstört werden, sobald seine letzte Referenz gelöscht ist; die Finalisierungs- und Löschschritte sind nicht notwendig, um ungenutzte Objekte sicher wiederzugewinnen. Es kann jedoch nützlich sein, tp_finalize und tp_clear vor der Zerstörung automatisch aufzurufen, da das Typdesign vereinfacht wird, wenn alle Objekte immer dieselbe Ereignisreihe durchlaufen, unabhängig davon, ob sie an einem zyklischen Isolat teilgenommen haben. Python ruft derzeit nur tp_finalize und tp_clear nach Bedarf auf, um ein zyklisches Isolat zu zerstören; dies kann sich in einer zukünftigen Version ändern.
Funktionen¶
Um Speicher zuzuweisen und freizugeben, siehe Objekte auf dem Heap zuweisen.
-
void PyObject_CallFinalizer(PyObject *op)¶
Finalisiert das Objekt wie in
tp_finalizebeschrieben. Rufen Sie diese Funktion (oderPyObject_CallFinalizerFromDealloc()) anstelle des direkten Aufrufs vontp_finalizeauf, da diese Funktion mehrere Aufrufe vontp_finalizededuplizieren kann. Derzeit werden Aufrufe nur dedupliziert, wenn der Typ Garbage Collection unterstützt (d. h. das FlagPy_TPFLAGS_HAVE_GCgesetzt ist); dies kann sich in Zukunft ändern.
-
int PyObject_CallFinalizerFromDealloc(PyObject *op)¶
Dasselbe wie
PyObject_CallFinalizer(), aber dafür bestimmt, am Anfang des Objekt-Destruktors (tp_dealloc) aufgerufen zu werden. Es dürfen keine Referenzen auf das Objekt vorhanden sein. Wenn der Finalizer des Objekts das Objekt wiederbelebt, gibt diese Funktion -1 zurück; es sollte keine weitere Zerstörung stattfinden. Andernfalls gibt diese Funktion 0 zurück und die Zerstörung kann normal fortgesetzt werden.Siehe auch
tp_deallocfür Beispielcode.