2011-11-06 12 views

Odpowiedz

23

Standardowy mechanizm liczenia referencji Pythona nie może zwolnić cykli, więc struktura w tym przykładzie wycieknie.

supplemental garbage collection facility jednak jest domyślnie włączona i powinna być w stanie uwolnić tę strukturę, jeśli żaden z jej elementów są dostępne z zewnątrz już i nie mają __del__() metod.

Jeśli tak, śmieciarka will not free them, ponieważ nie może określić bezpiecznego celu uruchomienia tych metod __del__().

+5

Należy wyraźnie stwierdzić, że GC, który nazywacie "uzupełniającym", jest domyślnie włączony w Pythonie –

+0

@Eli, masz rację, odpowiedź odpowiednio zaktualizowana. –

+3

Hurra! Przynajmniej narody (ty i Raymond Hettinger), którzy nie robią zamieszania wokół GC, a nie używają "garbage collector" jako synonimu "mechanizmu liczącego referencje"! Od dawna byłem zakłopotany faktem, że rozumiałem takie rzeczy, ale ciągle czytałem teksty, w których narody wyrażały swoje idee tak, jakby GC był odpowiedzialny za zabijanie niesklasyfikowanych obiektów. W twojej odpowiedzi różnica jest doskonale wyrażona i jasna. Dziękuję Ci. Stąd +1 – eyquem

5

Pythona GC jest przeznaczony do przechodzenia wszystkie ruchome obiekty zlokalizować i usunąć cykle odniesienia bez odniesienia zewnętrznego.

Można sprawdzić, czy tak się dzieje, uruchamiając gc.collect(), a następnie drukując gc.garbage i gc.get_objects.

2

Jeśli użyjesz słabych punktów dla swoich rodziców, GC stanie się normalne.

18

Aby nieco rozszerzyć odpowiedź Frédéric, the "reference counts" section dokumentów wyjaśnia ładnie detekcję cyklu dodatkowego.

Ponieważ uważam wyjaśniania rzeczy to dobry sposób, aby potwierdzić rozumiem, oto kilka przykładów ... Z tych dwóch klas:

class WithDel(object): 
    def __del__(self): 
     print "deleting %s object at %s" % (self.__class__.__name__, id(self)) 


class NoDel(object): 
    pass 

Tworzenie obiektu i utraty odwołanie od a wywołuje metodę __del__ dzięki ref liczenia:

>>> a = WithDel() 
>>> a = None # leaving the WithDel object with no references 
deleting WithDel object at 4299615184 

przypadku wprowadzenia pętla odniesienia między dwoma obiektami bez__del__ sposobu, całość pozostaje szczelny, t jego czas dzięki wykrywaniu cyklu.Po pierwsze, umożliwia wyjście śmieci zbierania debugowania:

>>> import gc 
>>> gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS) 

następnie dokonać pętla odniesienia między dwoma obiektami:

>>> a = NoDel(); b = NoDel() 
>>> a.other = b; b.other = a # cyclical reference 
>>> a = None; b = None # Leave only the reference-cycle 
>>> gc.collect() 
gc: collectable <NoDel 0x10046ed50> 
gc: collectable <NoDel 0x10046ed90> 
gc: collectable <dict 0x100376c20> 
gc: collectable <dict 0x100376b00> 
4 
>>> gc.garbage 
[] 

(dict wynosi od obiektów wewnętrzny atrybutu __dict__)

Wszystko jest w porządku, do nawet jeden z obiektów w cyklu zawiera metodę __del__:

>>> a = NoDel(); b = WithDel() 
>>> a.other = b; b.other = a 
>>> a = None; b = None 
>>> gc.collect() 
gc: uncollectable <WithDel 0x10046edd0> 
gc: uncollectable <dict 0x100376b00> 
gc: uncollectable <NoDel 0x10046ed90> 
gc: uncollectable <dict 0x100376c20> 
4 
>>> gc.garbage 
[<__main__.WithDel object at 0x10046edd0>] 

Jak wspomniano Paul, pętla może zostać uszkodzony z weakref:

>>> import weakref 
>>> a = NoDel(); b = WithDel() 
>>> a.other = weakref.ref(b) 
>>> b.other = a # could also be a weakref 

Potem, gdy odniesienie do obiektu WithDelb jest stracone, to zostanie usunięty, mimo cyklu:

>>> b = None 
deleting WithDel object at 4299656848 
>>> a.other 
<weakref at 0x10045b9f0; dead> 

Och, objgraph byłoby pomocne indicated the problematic __del__ method like this

+0

To działa dla mnie w python2, jednak w python3 nie mogę odtworzyć wycieku ... Czy coś się zmieniło? – kralyk

+0

@kralyk Myślę, że ten pep jest odpowiedzialny: https://www.python.org/dev/peps/pep-0442/ – ead

Powiązane problemy