Objekt uppståndelse

I objektorienterade programmeringsspråk med skräpinsamling är objektuppståndelse när ett objekt kommer tillbaka till liv under processen med objektförstöring , som en bieffekt av att en finalizer exekveras .

Objektuppståndelse orsakar ett antal problem , särskilt att möjligheten till föremålsuppståndelse – även om det inte inträffar – gör sophämtningen betydligt mer komplicerad och långsammare, och är en viktig anledning till att slutbehandlare avskräcks. Språk hanterar objekts uppståndelse på olika sätt . I sällsynta fall används objektuppståndelse för att implementera vissa designmönster, särskilt en objektpool , medan uppståndelse i andra fall är en oönskad bugg som orsakas av ett fel i slutbehandlare, och i allmänhet avråds återuppståndelse.

Bearbeta

Objektets återuppståndelse sker via följande process. För det första blir ett föremål skräp när det inte längre är tillgängligt från programmet och kan samlas in (förstöras och omallokeras). Sedan, under objektdestruktion, innan sopsamlaren omallokerar objektet, kan en slutbehandlingsmetod köras, som i sin tur kan göra att objektet eller ett annat sopobjekt (som kan nås från objektet med en slutbehandlare) kan nås igen genom att skapa referenser till det, som en finalizer kan innehålla godtycklig kod. Om detta händer är det refererade objektet – som inte nödvändigtvis är det slutgiltiga objektet – inte längre skräp och kan inte deallokeras, eftersom referenserna till det annars skulle bli dinglande referenser och orsaka fel när det används, generellt programkrasch eller oförutsägbart beteende. Istället, för att upprätthålla minnessäkerhet , återställs objektet till liv eller återuppstår.

För att upptäcka detta kommer en sophämtare i allmänhet att göra tvåfasinsamling i närvaro av slutbehandlare: först slutföra alla sopor som har en slutbehandlare och kontrollera sedan om allt skräp (eller allt skräp som kan nås från objekten med slutbehandlare ) . ifall finalisterna har återuppstått lite skräp. Detta lägger till overhead och fördröjer minnesåtervinning.

Uppståndna föremål

Ett återuppstått föremål kan behandlas på samma sätt som andra föremål, eller kan behandlas speciellt. På många språk, särskilt C#, Java och Python (från Python 3.4), slutförs objekt endast en gång, för att undvika möjligheten att ett objekt upprepade gånger återuppstår eller till och med är oförstörbart; i C# slutförs objekt med finalizers som standard endast en gång, men kan omregistreras för slutförande. I andra fall anses återuppståndna objekt som fel, särskilt i Objective-C; eller behandlas identiskt med andra objekt, särskilt i Python före Python 3.4.

Ett återuppstått objekt kallas ibland ett zombieobjekt eller zombie , men denna term används för olika objekttillstånd relaterade till objektförstörelse, med användning beroende på språk och författare. Ett "zombieobjekt" har dock en specialiserad betydelse i Objective-C , som beskrivs i detalj nedan. Zombieobjekt är något analoga med zombieprocesser , genom att de har genomgått en termineringstillståndsändring och är nära att deallokeras, men detaljerna är väsentligt annorlunda.

Varianter

I .NET Framework , särskilt C# och VB.NET, hänvisar "objektuppståndelse" istället till tillståndet för ett objekt under slutförandet: objektet återupplivas (från att vara otillgängligt), slutbehandlaren körs och returneras sedan till är otillgänglig (och är inte längre registrerad för framtida slutförande). I .NET spåras inte vilka objekt som behöver slutföras objekt-för-objekt, utan lagras istället i en slutförande "kö", så snarare än en föreställning om återuppståndna objekt i den här artikelns mening, talar man om objekt "köade för slutförande". Vidare kan objekt återställas i kö för slutförande via GC.ReRegisterForFinalize , varvid man var noga med att inte multiplicera köobjekt.

Mekanism

Det finns två huvudsakliga sätt som ett objekt kan återuppliva sig själv eller ett annat objekt: genom att skapa en referens till sig själv i ett objekt som det kan nå (skräp är inte tillgängligt, men skräp kan referera till icke-skräpobjekt), eller genom att skapa en referens i miljön ( globala variabler , eller i vissa fall statiska variabler eller variabler i en stängning ). Python-exempel på båda följer, för ett objekt som återuppstår. Det är också möjligt för ett objekt att återuppliva andra objekt om båda samlas in i en given sophämtningscykel, med samma mekanismer.

Återuppstår genom att skapa en referens i ett objekt som det kan nå:

 
        
          
        
     
         
              
        

    
                      
    
    
              
   klass  Clingy  :  def  __init__  (  själv  ,  ref  =  Ingen  )  ->  Ingen  :  själv  .  ref  =  ref  def  __del__  (  själv  ):  om  själv  .  ref  :  själv  .  ref  .  ref  =  självutskrift  (  "Lämna mig inte!"  )  a  =  Clingy  (  Clingy  ())  # Skapa en länkad lista med 2 element,  # refereras av |a  |  a  .  ref  .  ref  =  a  # Skapa en cykel  a  .  ref  =  Ingen  # Om du rensar referensen från den första noden  # till den andra blir det andra skräpet till  ett  .  ref  =  Ingen 

Återuppstår genom att skapa en referens i den globala miljön:

  
 
     
         
          
        

  
    
   c  =  Ingen  klass  Odödlig  :  def  __del__  (  själv  ):  global  c  c  =  självutskrift  (  "Jag är inte död ännu."  )  c  =  Odödlig  ()  c  =  Ingen  # Rensning |c  |  gör objektet skräp  c  =  Ingen 

I exemplen ovan, i CPython före 3.4, kommer dessa att köra finalizers upprepade gånger, och objekten kommer inte att samlas in, medan i CPython 3.4 och senare kommer finalizers bara att anropas en gång, och objekten kommer att skräpsamlas andra gången blir de oåtkomliga.

Problem

Objektets uppståndelse orsakar ett stort antal problem.

Försvårar sophämtningen
Möjligheten till återuppståndelse av föremål innebär att sophämtaren måste söka efter återuppståndna föremål efter slutförande – även om det faktiskt inte inträffar – vilket försvårar och bromsar sophämtningen.
Oförstörbara föremål
Under vissa omständigheter kan ett föremål vara oförstörbart: om ett föremål återuppstår i sin egen färdigställare (eller en grupp av föremål återuppstår varandra som ett resultat av deras färdigställare), och slutföraren alltid anropas när föremålet förstörs, då objekt kan inte förstöras och dess minne kan inte återtas.
Oavsiktlig återuppståndelse och läckor
För det tredje kan återuppståndelse av föremål vara oavsiktlig, och det resulterande föremålet kan vara semantiskt skräp, och därför aldrig faktiskt samlat in, vilket orsakar en logisk minnesläcka .
Inkonsekvent tillstånd och återinitiering
Ett återuppstått objekt kan vara i ett inkonsekvent tillstånd, eller bryta mot klassinvarianter , på grund av att finalizern har körts och orsakar ett oregelbundet tillstånd. Sålunda måste återuppståndna objekt i allmänhet återinitieras manuellt.
Unik slutförande eller omslutförande
I vissa språk (som Java och Python 3.4+) sker garanterat slutförande exakt en gång per objekt, så återuppståndna objekt kommer inte att få sina slutbehandlare anropade; därför måste återuppståndna objekt köra all nödvändig rensningskod utanför slutbehandlaren. På vissa andra språk kan programmeraren tvinga slutförandet att göras upprepade gånger; särskilt har C# GC.ReRegisterForFinalize .

Lösningar

Språk har antagit flera olika metoder för att hantera föremåls uppståndelse, oftast genom att ha två-fas sophämtning i närvaro av slutbehandlare, för att förhindra dinglande referenser; och genom att endast slutföra objekt en gång, särskilt genom att markera objekt som slutförda (via en flagga), för att säkerställa att objekt kan förstöras.

Java kommer inte att frigöra objektet förrän det har bevisat att objektet återigen är oåtkomligt, men kommer inte att köra finalizern mer än en gång.

I Python, före Python 3.4, skulle standardimplementeringen av CPython behandla återuppståndna objekt identiskt med andra objekt (som aldrig hade slutförts), vilket gör oförstörbara objekt möjliga. Vidare skulle det inte skräpa samla cykler som innehöll ett objekt med en slutbehandlare, för att undvika eventuella problem med objektets återuppståndelse. Från och med Python 3.4 är beteendet i stort sett detsamma som Java: objekt slutförs bara en gång (markeras som "redan slutförda"), sophämtning av cykler är i två faser, med den andra fasen som kontrollerar efter återuppståndna objekt.

Objective-C 2.0 kommer att försätta återuppståndna objekt i ett "zombie"-tillstånd, där de loggar alla meddelanden som skickas till dem, men inte gör något annat. Se även Automatisk referensräkning: Nollställning av svaga referenser för hantering av svaga referenser .

I .NET Framework, i synnerhet C# och VB.NET, bestäms objektslutförandet av en slutförande "kö", som kontrolleras under objektdestruktion. Objekt med en finalizer placeras i den här kön när de skapas och ställs ur kö när finalizern anropas, men kan manuellt avköas (före finalisering) med SuppressFinalize eller återställas i kö med ReRegisterForFinalize . Sålunda slutförs objekt med finalizers som standard högst en gång, men denna slutbehandling kan undertryckas, eller objekt kan slutföras flera gånger om de återuppstår (görs tillgängliga igen) och sedan återställs i kö för slutförande. Vidare svaga referenser som standard inte återuppståndelse, vilket innebär att en svag referens inte uppdateras om ett objekt återuppstår; dessa kallas korta svaga referenser och svaga referenser som spårar uppståndelse kallas långa svaga referenser .

Ansökningar

Objektuppståndelse är användbart för att hantera en objektpool av vanliga objekt, men det skymmer kod och gör det mer förvirrande. Den ska endast användas för föremål som kan komma att användas ofta och där konstruktionen/destruktionen av den är tidskrävande. Ett exempel kan vara en array av slumptal, där ett stort antal av dem skapas och förstörs på kort tid, men där faktiskt bara ett litet antal används samtidigt. Med objektuppståndelse skulle en poolteknik minska den onödiga omkostnaden för skapande och förstörelse. Här skulle en poolhanterare komma in på sin objektstackinformation i form av en referens till objektet, om det för närvarande ska förstöras. Poolhanteraren kommer att behålla objektet för återanvändning senare.

Se även

Anteckningar