Garbage collector i cykliczne odwołania
Proszę poznać sposób, w jaki moduł gc obsługuje cykle odwołań.
Garbage collector i cykliczne odwołania to bezpłatna lekcja Python Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Python Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Python Academy zawiera 4 lekcji w sumie.
Dlaczego zliczanie referencji nie wystarcza
Zliczanie referencji nie może zwolnić obiektów uczestniczących w cyklach referencji — każdy z nich przechowuje referencję do drugiego, więc żaden licznik nie spada do 0.
# Reference cycle: a → b → a
a = {}
b = {"other": a}
a["other"] = b
del a, b
# Both objects are unreachable but refcount > 0
# Only the cyclic GC can collect themModuł gc
gc to cykliczny garbage collector. Okresowo skanuje śledzone obiekty w poszukiwaniu nieosiągalnych cykli i je zbiera.
import gc
gc.collect() # trigger immediately
print(gc.garbage) # objects with __del__ in cycles (cannot auto-collect)Zbieranie generacyjne
GC używa trzech generacji. Nowe obiekty trafiają do generacji 0. Obiekty, które przetrwają zbieranie, są przenoszone do wyższej generacji. Generacja 0 jest zbierana najczęściej.
import gc
print(gc.get_count()) # (gen0, gen1, gen2) allocations since last collection
print(gc.get_threshold()) # (700, 10, 10) — thresholds for each generation
gc.set_threshold(1000, 15, 10) # tuneWykrywanie cykli za pomocą gc.get_referents
Proszę sprawdzać, do których obiektów odwołuje się dany obiekt — ułatwia to zrozumienie, dlaczego coś nie jest zbierane.
import gc
a = []
b = [a]
a.append(b)
for ref in gc.get_referents(a):
print(ref) # shows bgc.get_objects()
gc.get_objects() zwraca wszystkie obiekty aktualnie śledzone przez GC. Jest to przydatne podczas wyszukiwania wycieków pamięci.
import gc
before = len(gc.get_objects())
create_lots_of_objects()
after = len(gc.get_objects())
print(f"Leaked: {after - before} objects")Unikanie cykli
Struktury danych należy projektować tak, aby unikać cykli: proszę używać weakrefs dla odwołań zwrotnych, identyfikatorów zamiast bezpośrednich referencji albo jawnie przerywać cykle, zanim obiekty wyjdą poza zakres.
import weakref
class Node:
def __init__(self, parent):
# weakref avoids cycle:
self.parent = weakref.ref(parent)
class Tree:
def __init__(self):
self.child = Node(self) # no hard cycle__del__ a cykle
Obiekty z __del__, które uczestniczą w cyklu, nie mogą zostać automatycznie zebrane. Zamiast tego trafiają do gc.garbage.
import gc
class Leaky:
def __del__(self): pass
a = Leaky()
b = Leaky()
a.other = b
b.other = a
del a, b
gc.collect()
print(gc.garbage) # [Leaky, Leaky] — cannot collectgc.freeze() — Python 3.7+
gc.freeze() zamraża aktualnie śledzone obiekty, dzięki czemu nigdy nie są zbierane. Jest to przydatne w długo działających procesach po uruchomieniu programu, aby zmniejszyć przerwy powodowane przez GC.
import gc
# After all globals and imports are in place:
gc.freeze() # no GC scanning for these objects ever again
# Useful for: gunicorn pre-fork, background serversWyłączanie i ponowne włączanie GC
W ciasnych pętlach, w których wiadomo, że nie występują cykle, należy wyłączyć cykliczny GC, a następnie ponownie go włączyć i wymusić zbieranie.
import gc
gc.disable()
try:
result = tight_loop_no_cycles()
finally:
gc.enable()
gc.collect()isenabled i isfinalized
Stan GC można sprawdzić za pomocą gc.isenabled(), a to, czy obiekt został sfinalizowany, za pomocą gc.is_finalized(obj).
import gc
print(gc.isenabled()) # True by default
obj = object()
print(gc.is_finalized(obj)) # False (still alive)Typowe przyczyny wycieków pamięci
Typowe przyczyny wycieków pamięci w Pythonie to: globalne pamięci podręczne rosnące bez ograniczeń, nieodłączone odbiorniki zdarzeń, cykliczne referencje z __del__ oraz rozszerzenia C, które wyciekają referencje.
# Typical leaks:
global_cache = {} # grows forever — use lru_cache with maxsize
class EventBus:
listeners = []
# Listeners hold references to objects:
# @classmethod
# def on(cls, fn): cls.listeners.append(fn)
# Must call off() to detachSzybkie sprawdzenie
Co dzieje się z obiektami zawierającymi __del__, które uczestniczą w cyklu referencji?
Podsumowanie
Cykliczny GC obsługuje cykle referencji, z którymi nie radzi sobie zliczanie referencji. Używa trzech generacji i przenosi obiekty, które przetrwały, do wyższych generacji. Cykli należy unikać, korzystając z weakrefs. Obiekty z __del__ należące do cykli trafiają do gc.garbage. Po uruchomieniu programu warto użyć gc.freeze(), aby zmniejszyć przerwy powodowane przez GC w długo działających serwerach.
Często zadawane pytania
Czy lekcja „Garbage collector i cykliczne odwołania” jest bezpłatna?
Tak — pełny tekst „Garbage collector i cykliczne odwołania” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Python Academy, przejdź na CoddyKit PRO. Kurs Python Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Garbage collector i cykliczne odwołania”?
Proszę poznać sposób, w jaki moduł gc obsługuje cykle odwołań. Ćwiczysz Python Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Python Academy?
Nie wymagamy żadnego doświadczenia. Python Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Garbage collector i cykliczne odwołania”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Python Academy?
Tak. Każda lekcja Python Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Zliczanie odwołań w CPythonie
- Garbage collector i cykliczne odwołania
- Profilowanie za pomocą cProfile i line_profiler
- Profilowanie pamięci za pomocą tracemalloc