2010-04-05 15 views
6

Sto cercando di capire l'interno del garbage collector CPython, in particolare quando viene chiamato il distruttore. Finora, il comportamento è intuitivo, ma il caso seguente mi fa saltar su:Perché viene chiamato il distruttore quando il garbage collector CPython è disabilitato?

  1. Disabilitare il GC.
  2. Creare un oggetto, quindi rimuovere un riferimento ad esso.
  3. L'oggetto viene distrutto e viene chiamato il metodo _____del_____.

Ho pensato che questo sarebbe successo solo se il garbage collector era abilitato. Qualcuno può spiegare perché questo accade? C'è un modo per rimandare chiamando il distruttore?

import gc 
import unittest 

_destroyed = False 

class MyClass(object): 

    def __del__(self): 
     global _destroyed 
     _destroyed = True 

class GarbageCollectionTest(unittest.TestCase): 

    def testExplicitGarbageCollection(self): 
     gc.disable() 
     ref = MyClass() 
     ref = None 
     # The next test fails. 
     # The object is automatically destroyed even with the collector turned off. 
     self.assertFalse(_destroyed) 
     gc.collect() 
     self.assertTrue(_destroyed) 

if __name__=='__main__': 
    unittest.main() 

Esonero di responsabilità: questo codice non è pensato per la produzione - ho già notato che questo è molto implementazione specifici e non funziona su Jython.

risposta

9

Python ha sia riferimento conteggio garbage collection e ciclico raccolta dei rifiuti, ed è quest'ultimo che le gc controlli modulo. Il conteggio dei riferimenti non può essere disattivato e quindi accade ancora quando il garbage collector ciclico è disattivato.

Poiché non vi sono riferimenti all'oggetto dopo lo ref = None, il suo metodo __del__ viene chiamato come risultato del suo conteggio di riferimento che va a zero.

C'è un indizio in the documentation: "Dal momento che il collezionista integratori il conteggio di riferimento già utilizzato in Python ..." (il corsivo è mio).

È possibile interrompere la prima affermazione di sparare, rendendo l'oggetto si riferisce a se stesso, in modo che il conteggio dei riferimenti non va a zero, ad esempio indicando che questo costruttore:

def __init__(self): 
    self.myself = self 

Ma se si fallo, la seconda asserzione sparerà. Questo perché i cicli di spazzatura con i metodi __del__ non vengono raccolti: consultare la documentazione di gc.garbage.

4

In base alla propria definizione di garbage collector, CPython ha due garbage collector, uno di riferimento e l'altro.
Il contatore di riferimento è sempre funzionante e non può essere disattivato poiché è piuttosto veloce e leggero che non influisce in modo significativo sul tempo di esecuzione del sistema.
L'altro (qualche variante di spunta e spaziatura, penso), viene eseguito ogni tanto e può essere disabilitato. Questo perché richiede che l'interprete venga messo in pausa mentre è in esecuzione, e ciò può accadere nel momento sbagliato e consumare un bel po 'di tempo della CPU.
Questa possibilità di disattivarlo è lì per quei tempi in cui si prevede di fare qualcosa che è cruciale in termini di tempo e la mancanza di questo GC non causerà alcun problema.

+0

È questa implementazione "due garbage collector" documentata da qualche parte? – Frederik

+0

Dai un'occhiata alla risposta di Alex Martelli e ai suoi collegamenti associati. Probabilmente è meglio di qualsiasi altra cosa potrei inventarmi. –

4

La documentazione here spiegano come quello che viene chiamato "il garbage collector optional" è in realtà un collezionista di ciclico spazzatura (il genere che il conteggio di riferimento non avrebbe raggiunto).conteggio di riferimento viene spiegato here, con un cenno alla sua interazione con la gc ciclico:

Mentre Python usa il tradizionale attuazione conteggio riferimento, offre anche un rilevatore di ciclo che funziona per rilevare cicli di riferimento. Questo consente alle applicazioni di non preoccuparsi di creazione di riferimenti circolari diretti o indiretti ; questi sono i punti deboli della garbage collection implementata utilizzando il conteggio di riferimento . I cicli di riferimento sono costituiti da oggetti che contengono riferimenti (eventualmente indiretti) a se stessi, in modo che ogni oggetto nel numero abbia un conteggio di riferimento che è diverso da zero. Tipici riferimento implementazioni di conteggio non sono in grado di recuperare la memoria appartenenti a qualsiasi oggetti in un ciclo di riferimento, o riferimento dagli oggetti nel ciclo , anche se non vi sono ulteriori riferimenti al ciclo stessa.

Problemi correlati