Objektets livscykel¶
I det här avsnittet förklaras hur en typs slots förhåller sig till varandra under ett objekts hela livstid. Det är inte avsett att vara en fullständig kanonisk referens för slotsen; hänvisa istället till slotspecifik dokumentation i Typobjektstrukturer för detaljer om en viss slot.
Livshändelser¶
Figuren nedan illustrerar ordningen på de händelser som kan inträffa under ett objekts liv. En pil från A till B anger att händelse B kan inträffa efter att händelse A har inträffat, och pilens etikett anger det villkor som måste vara sant för att B ska inträffa efter A.
Förklaring:
När ett nytt objekt konstrueras genom att anropa dess typ:
tp_new
anropas för att skapa ett nytt objekt.tp_alloc
anropas direkt avtp_new
för att allokera minne till det nya objektet.tp_init
initierar det nyskapade objektet.tp_init
kan anropas igen för att återinitialisera ett objekt, om så önskas. Anropet avtp_init
kan också hoppas över helt, till exempel genom att Python-kod anropar__new__()
.
När
tp_init
har slutförts är objektet klart att användas.En tid efter att den sista referensen till ett objekt har tagits bort:
Om ett objekt inte är markerat som finalized kan det finaliseras genom att markera det som finalized och anropa dess
tp_finalize
-funktion. Python finaliserar inte ett objekt när den sista referensen till det tas bort; användPyObject_CallFinalizerFromDealloc()
för att säkerställa atttp_finalize
alltid anropas.Om objektet är markerat som finalized kan
tp_clear
anropas av garbage collector för att rensa referenser som objektet har. Den anropas inte när objektets referensantal når noll.tp_dealloc
anropas för att förstöra objektet. För att undvika dubbelkodning anropartp_dealloc
vanligtvistp_clear
för att frigöra objektets referenser.När
tp_dealloc
avslutar objektdestruktionen anropar den direkttp_free
(vanligtvis inställd påPyObject_Free()
ellerPyObject_GC_Del()
automatiskt beroende på vad som är lämpligt för typen) för att avallokera minnet.
Funktionen
tp_finalize
får lägga till en referens till objektet om så önskas. Om den gör det återupplivas objektet, vilket förhindrar att det förstörs i väntan på detta. (Endasttp_finalize
får återuppliva ett objekt;tp_clear
ochtp_dealloc
kan inte göra det utan att anropatp_finalize
) Att återuppliva ett objekt kan eller kan inte leda till att objektets finalized-markering tas bort. För närvarande tar Python inte bort finalized-markeringen från ett återuppväckt objekt om det stöder garbage collection (dvs. flagganPy_TPFLAGS_HAVE_GC
är inställd) men tar bort markeringen om objektet inte stöder garbage collection; endera eller båda av dessa beteenden kan ändras i framtiden.tp_dealloc
kan valfritt anropatp_finalize
viaPyObject_CallFinalizerFromDealloc()
om den vill återanvända den koden för att hjälpa till med objektdestruktion. Detta rekommenderas eftersom det garanterar atttp_finalize
alltid anropas före destruktion. Se dokumentationen förtp_dealloc
för exempelkod.Om objektet ingår i ett cyclic isolate och antingen
tp_clear
misslyckas med att bryta referenscykeln eller så upptäcks inte det cykliska isolatet (kanske anropadesgc.disable()
, eller så utelämnades flagganPy_TPFLAGS_HAVE_GC
felaktigt i en av de inblandade typerna), förblir objekten på obestämd tid omöjliga att samla in (de ”läcker”). Segc.garbage
.
Om objektet är markerat som stödjande garbage collection (flaggan Py_TPFLAGS_HAVE_GC
är inställd i tp_flags
), är följande händelser också möjliga:
Skräpsamlaren anropar ibland
tp_traverse
för att identifiera cyclic isolates.När skräpsamlaren upptäcker en cyclic isolate, finaliserar den ett av objekten i gruppen genom att markera det som finaliserat och anropa dess
tp_finalize
-funktion, om den har en sådan. Detta upprepas tills det cykliska isolatet inte existerar eller tills alla objekt har slutförts.tp_finalize
får återuppliva objektet genom att lägga till en referens från utanför cyclic isolate. Den nya referensen gör att gruppen av objekt inte längre utgör ett cykliskt isolat (referenscykeln kan fortfarande existera, men om den gör det är objekten inte längre isolerade).När skräpsamlaren upptäcker en cyclic isolate och alla objekt i gruppen redan har markerats som finaliserade, rensar skräpsamlaren ett eller flera av de orensade objekten i gruppen (eventuellt samtidigt) genom att anropa varje
tp_clear
-funktion. Detta upprepas så länge som det cykliska isolatet fortfarande existerar och inte alla objekt har rensats.
Destruktion av cykliska isolat¶
Nedan listas livsstadierna för en hypotetisk cyklisk isolat som fortsätter att existera efter att varje medlemsobjekt har slutförts eller rensats. Det är en minnesläcka om en cyklisk isolat går igenom alla dessa stadier; den bör försvinna när alla objekt har rensats, om inte förr. En cyklisk isolat kan försvinna antingen för att referenscykeln bryts eller för att objekten inte längre är isolerade på grund av finalizer-uppståndelse (se tp_finalize
).
Reachable (ännu inte en cyklisk isolat): Alla objekt befinner sig i sitt normala, nåbara tillstånd. En referenscykel kan existera, men en extern referens innebär att objekten ännu inte är isolerade.
Unreachable but consistent: Den slutliga referensen från utanför den cykliska gruppen av objekt har tagits bort, vilket gör att objekten blir isolerade (en cyklisk isolat har alltså uppstått). Inget av gruppens objekt har slutförts eller klargjorts ännu. Det cykliska isolatet förblir i detta skede tills någon framtida körning av skräpsamlaren (inte nödvändigtvis nästa körning eftersom nästa körning kanske inte skannar alla objekt).
Mix av färdigställda och icke färdigställda: Objekten i en cyklisk isolat färdigställs ett i taget, vilket innebär att det finns en tidsperiod då den cykliska isolaten består av en mix av färdigställda och icke färdigställda objekt. Slutförandets ordning är ospecificerad, så det kan verka slumpmässigt. Ett finaliserat objekt måste bete sig på ett förnuftigt sätt när icke-finaliserade objekt interagerar med det, och ett icke-finaliserat objekt måste kunna tolerera att en godtycklig delmängd av dess referenter finaliseras.
All finalized: Alla objekt i en cyklisk isolat är finalized innan någon av dem rensas.
Mix av finalized och cleared: Objekten kan rensas seriellt eller samtidigt (men med GIL kvar); oavsett vilket kommer vissa att avslutas före andra. Ett färdigställt objekt måste kunna tolerera att en delmängd av dess referenter rensas. PEP 442 kallar detta steg för ”cykliskt skräp”.
Leaked: Om en cyklisk isolat fortfarande existerar efter att alla objekt i gruppen har slutförts och rensats, förblir objekten på obestämd tid omöjliga att samla in (se
gc.garbage
). Det är ett fel om en cyklisk isolat når detta stadium - det betyder atttp_clear
-metoderna för de deltagande objekten inte har lyckats bryta referenscykeln som krävs.
Om tp_clear
inte existerade, skulle Python inte ha något sätt att säkert bryta en referenscykel. Att helt enkelt förstöra ett objekt i en cyklisk isolat skulle resultera i en dinglande pekare, vilket utlöser odefinierat beteende när ett objekt som refererar till det förstörda objektet själv förstörs. Rensningssteget gör objektförstöringen till en tvåfasprocess: först anropas tp_clear
för att delvis förstöra objekten tillräckligt för att skilja dem från varandra, sedan anropas tp_dealloc
för att slutföra förstöringen.
Till skillnad från clearing är finalization inte en fas av förstörelse. Ett finalized-objekt måste fortfarande uppföra sig korrekt genom att fortsätta uppfylla sina designkontrakt. Ett objekts finalizer får exekvera godtycklig Python-kod och får till och med förhindra den förestående destruktionen genom att lägga till en referens. Finalizer är endast relaterad till destruktion genom anropsordning—om den körs, körs den före destruktion, som börjar med tp_clear
(om den anropas) och avslutas med tp_dealloc
.
Finalization-steget är inte nödvändigt för att på ett säkert sätt återta objekten i en cyklisk isolat, men dess existens gör det lättare att designa typer som beter sig på ett vettigt sätt när objekt rensas. Att rensa ett objekt kan nödvändigtvis lämna det i ett trasigt, delvis förstört tillstånd - det kan vara osäkert att anropa någon av det rensade objektets metoder eller komma åt något av dess attribut. Med finalization kan endast finalized-objekt eventuellt interagera med clearade objekt; non-finalized-objekt garanteras att interagera med endast icke-clearade (men potentiellt finalized) objekt.
För att sammanfatta de möjliga interaktionerna:
Ett icke-finaliserat objekt kan ha referenser till eller från icke-finaliserade och finaliserade objekt, men inte till eller från rensade objekt.
Ett finalized-objekt kan ha referenser till eller från non-finalized-, finalized- och cleared-objekt.
Ett avklarat objekt kan ha referenser till eller från färdigbehandlade och avklarade objekt, men inte till eller från icke färdigbehandlade objekt.
Utan några referenscykler kan ett objekt helt enkelt förstöras när dess sista referens har tagits bort; stegen finalization och clearing är inte nödvändiga för att på ett säkert sätt återta oanvända objekt. Det kan dock vara användbart att automatiskt anropa tp_finalize
och tp_clear
innan destruktion eftersom typdesign förenklas när alla objekt alltid upplever samma serie händelser oavsett om de deltog i en cyklisk isolat. Python anropar för närvarande bara tp_finalize
och tp_clear
när det behövs för att förstöra ett cykliskt isolat; detta kan ändras i en framtida version.
Funktioner¶
För att allokera och frigöra minne, se Tilldela objekt på heapen.
-
void PyObject_CallFinalizer(PyObject *op)¶
Finaliserar objektet enligt beskrivningen i
tp_finalize
. Anropa denna funktion (ellerPyObject_CallFinalizerFromDealloc()
) istället för att anropatp_finalize
direkt eftersom denna funktion kan avdubbla flera anrop tilltp_finalize
. För närvarande dedupliceras anrop endast om typen stöder garbage collection (dvs. om flagganPy_TPFLAGS_HAVE_GC
är inställd); detta kan komma att ändras i framtiden.
-
int PyObject_CallFinalizerFromDealloc(PyObject *op)¶
Samma som
PyObject_CallFinalizer()
men avsedd att anropas i början av objektets destruktor (tp_dealloc
). Det får inte finnas några referenser till objektet. Om objektets finalizer återupplivar objektet returnerar denna funktion -1; ingen ytterligare destruktion bör ske. I annat fall returnerar denna funktion 0 och destruktionen kan fortsätta normalt.Se även
tp_dealloc
för exempelkod.