gc en Python: controla el recolector

Publicado el: 16/08/2026
Tempo de leitura: 7 minutos
Módulo de memoria RAM que representa gestión de objetos con gc en Python

El módulo gc en Python expone la interfaz del recolector de ciclos de CPython. El intérprete ya libera la mayoría de los objetos mediante conteo de referencias, pero ciclos como “el objeto A apunta a B y B vuelve a apuntar a A” pueden permanecer incluso cuando la aplicación perdió todas las referencias externas. El recolector complementario identifica esos grupos inalcanzables e intenta liberarlos.

La mayoría de los programas debería conservar la configuración predeterminada. La API resulta útil para investigar fugas de memoria, servicios de larga duración, servidores prefork, pruebas con estructuras cíclicas y observabilidad de pausas del recolector.

Conteo de referencias y ciclos

Cuando desaparece la última referencia a un objeto común, CPython normalmente lo destruye de inmediato. Un ciclo impide que los contadores lleguen a cero.

class Nodo:
    def __init__(self, nombre):
        self.nombre = nombre
        self.siguiente = None

a = Nodo("a")
b = Nodo("b")
a.siguiente = b
b.siguiente = a

del a, b

Después de del, el programa ya no puede alcanzar los nodos, pero ellos continúan referenciándose. Una recolección cíclica posterior puede eliminarlos.

Comprueba si está activo

import gc

print(gc.isenabled())

gc.enable() activa la recolección automática y gc.disable() la desactiva. Deshabilitar el recolector no desactiva el conteo de referencias; solo suspende la búsqueda de ciclos.

No lo desactives sin medir

Una aplicación que demostró no crear ciclos puede desactivar temporalmente el recolector durante una sección sensible a latencia. La restauración debe estar garantizada.

estaba_activo = gc.isenabled()
try:
    gc.disable()
    ejecutar_seccion_controlada()
finally:
    if estaba_activo:
        gc.enable()

Si alguna dependencia crea ciclos durante ese intervalo, permanecerán hasta una recolección futura. No uses esta técnica como optimización genérica.

Fuerza una recolección

gc.collect() ejecuta una recolección completa por defecto y devuelve la suma de objetos recolectados y no recolectables.

procesados = gc.collect()
print(f"Objetos procesados: {procesados}")

Llamadas manuales frecuentes pueden reducir el rendimiento. Úsalas en pruebas, diagnósticos y puntos de ciclo de vida cuidadosamente elegidos, no después de cada petición.

Selecciona una generación

El recolector agrupa objetos según cuántas recolecciones sobreviven. Los objetos nuevos entran en la generación joven y los supervivientes avanzan a generaciones antiguas.

gc.collect(0)
gc.collect(1)
gc.collect(2)

El comportamiento de la generación intermedia cambió durante la serie Python 3.14. El código que dependa de detalles generacionales debe probarse en la versión exacta. Las recolecciones completas también limpian varias free lists internas, aunque algunos objetos, como floats, pueden permanecer.

Consulta estadísticas

gc.get_stats() devuelve un diccionario por generación con cantidad de recolecciones, objetos recogidos y objetos no recolectables.

for generacion, datos in enumerate(gc.get_stats()):
    print(generacion, datos)

Observa tendencias bajo cargas comparables. Una lectura aislada no demuestra una fuga. Relaciona los datos con memoria del proceso y volumen de trabajo.

Consulta contadores y thresholds

print(gc.get_count())
print(gc.get_threshold())

get_count() muestra contadores actuales de asignaciones. get_threshold() informa los límites de la heurística automática.

Ajusta thresholds con cuidado

gc.set_threshold() cambia la frecuencia. Establecer el primer límite en cero desactiva la recolección automática.

anteriores = gc.get_threshold()
try:
    gc.set_threshold(1000, 15, 15)
    ejecutar_carga()
finally:
    gc.set_threshold(*anteriores)

Valores menores recolectan con mayor frecuencia y añaden overhead. Valores mayores reducen pausas y pueden elevar la memoria. Los builds free-threaded también consideran crecimiento de memoria y asignaciones netas.

Usa callbacks para observabilidad

gc.callbacks contiene funciones llamadas antes y después de cada recolección.

import time

inicios = {}

def observar(fase, info):
    generacion = info["generation"]
    if fase == "start":
        inicios[generacion] = time.perf_counter()
    else:
        duracion = time.perf_counter() - inicios.pop(generacion, 0)
        print(
            generacion,
            info["collected"],
            info["uncollectable"],
            duracion,
        )

gc.callbacks.append(observar)

Los callbacks se ejecutan durante una operación sensible. Deben ser rápidos y evitar red, locks, exceso de logs y muchas asignaciones. Elimínalos al terminar el diagnóstico.

Activa flags de debug

gc.set_debug() habilita información en stderr.

gc.set_debug(gc.DEBUG_STATS)

DEBUG_COLLECTABLE y DEBUG_UNCOLLECTABLE imprimen objetos encontrados. La salida puede ser enorme y contener datos sensibles.

DEBUG_LEAK y DEBUG_SAVEALL

DEBUG_LEAK combina varias flags e incluye DEBUG_SAVEALL. En ese modo, los objetos inalcanzables se agregan a gc.garbage en lugar de liberarse.

gc.set_debug(gc.DEBUG_LEAK)
gc.collect()
print(len(gc.garbage))

Esto incrementa la memoria intencionalmente. Después de inspeccionar, restaura las flags, limpia la lista y recolecta otra vez.

gc.set_debug(0)
gc.garbage.clear()
gc.collect()

Comprende gc.garbage

Desde la PEP 442, los objetos Python con __del__() normalmente siguen siendo recolectables incluso dentro de ciclos. La lista suele estar vacía salvo extensiones C específicas o cuando DEBUG_SAVEALL está activo.

No ignores una lista no vacía. Registra tipos de manera segura sin serializar objetos arbitrarios ni llamar sus métodos.

Comprueba si un objeto está rastreado

gc.is_tracked() informa si participa en la recolección cíclica.

print(gc.is_tracked(10))
print(gc.is_tracked([]))
print(gc.is_tracked({"clave": 1}))

Los tipos atómicos normalmente no se rastrean. Algunos contenedores simples pueden quedar fuera como optimización y volver a rastrearse al contener valores complejos.

Lista objetos rastreados

gc.get_objects() devuelve objetos rastreados, opcionalmente de una generación.

objetos = gc.get_objects()
print(len(objetos))

La lista puede ser enorme, aumenta temporalmente la memoria y revela estado interno. Úsala en un proceso de diagnóstico, filtra por tipo y no publiques su contenido mediante endpoints administrativos desprotegidos.

Encuentra referenciadores

gc.get_referrers(objetivo) devuelve containers rastreados que apuntan directamente al objetivo.

gc.collect()
referenciadores = gc.get_referrers(objetivo)
for item in referenciadores:
    print(type(item))

El resultado puede incluir frames del depurador, el propio código de inspección y objetos parcialmente construidos. La documentación recomienda usarlo solo para debugging. Evita llamar métodos de los objetos retornados.

Encuentra referentes

gc.get_referents() devuelve objetos visitados por el protocolo C tp_traverse.

for item in gc.get_referents(objetivo):
    print(type(item))

No representa necesariamente todas las referencias semánticas. Contiene las que el tipo presenta al recolector para detectar ciclos.

Finalización y resurrección

gc.is_finalized() indica si el finalizador ya se ejecutó. Un __del__() problemático puede resucitar el objeto guardándolo nuevamente.

resucitado = None

class Lazaro:
    def __del__(self):
        global resucitado
        resucitado = self

obj = Lazaro()
del obj
gc.collect()
print(gc.is_finalized(resucitado))

Evita lógica compleja en __del__(). Prefiere context managers, close() explícito y weakref.finalize(). Consulta weakref en Python.

Congela antes de fork

gc.freeze() mueve objetos rastreados a una generación permanente ignorada por recolecciones futuras. En servidores que usan fork() sin exec(), puede mejorar el uso de copy-on-write.

gc.disable()
cargar_aplicacion()
gc.freeze()
pid = os.fork()
if pid == 0:
    gc.enable()

El patrón exige arquitectura deliberada: desactiva temprano en el padre, congela justo antes del fork y reactiva en los hijos. No se aplica a todos los despliegues.

Descongela cuando sea necesario

gc.unfreeze() devuelve objetos permanentes a la generación antigua. gc.get_freeze_count() muestra cuántos están congelados.

print(gc.get_freeze_count())
gc.unfreeze()

Descongelar puede provocar una gran recolección posterior. Mide memoria y latencia.

GC y fugas de memoria

No todo crecimiento procede de ciclos. Caches, colas, registros, buffers, módulos, pools y variables globales pueden conservar referencias válidas. El recolector no libera objetos todavía alcanzables.

Usa tracemalloc en Python para comparar snapshots y después inspecciona referencias de tipos sospechosos.

Cuenta objetos por tipo

from collections import Counter

conteo = Counter(type(obj).__name__ for obj in gc.get_objects())
for nombre, total in conteo.most_common(20):
    print(nombre, total)

Toma snapshots en momentos equivalentes. La propia inspección crea objetos y distorsiona diferencias pequeñas.

Evita ciclos innecesarios

Callbacks, closures, observers, grafos padre-hijo y tareas crean ciclos con facilidad. Usa referencias débiles cuando una relación no representa propiedad. Elimina listeners y tareas al cerrar componentes.

Consulta también la guía sobre fugas de memoria en Python.

No llames collect en cada petición

Una recolección completa por petición suele reducir throughput y aumentar latencia. Si la memoria solo baja tras collect(), investiga por qué se crean tantos ciclos o por qué los thresholds no acompañan la carga.

Seguridad y auditoría

get_objects(), get_referrers() y get_referents() emiten eventos de auditoría y pueden revelar secretos. Limita su uso a administradores, logs protegidos y entornos de diagnóstico.

Buenas prácticas

  • Mantén la recolección automática activa por defecto.
  • Mide antes de ajustar thresholds.
  • Usa callbacks ligeros para métricas.
  • Limpia flags y gc.garbage tras depurar.
  • Usa referenciadores solo para diagnóstico.
  • Prefiere gestión explícita de recursos.
  • Usa tracemalloc para localizar crecimiento.
  • Prueba en la versión exacta de Python.

Conclusión

gc en Python permite observar y controlar el recolector cíclico que complementa el conteo de referencias de CPython. Estadísticas, callbacks, flags, inspección y congelación ayudan en diagnósticos avanzados.

Usa la interfaz con cuidado porque añade overhead y expone objetos internos. Consulta la documentación oficial de gc y la guía de diseño del garbage collector de CPython.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Líneas de código fuente que representan rastreo de ejecución con trace en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    trace en Python: rastrea ejecución

    Aprende trace en Python para contar líneas, seguir la ejecución, listar funciones, combinar cobertura y filtrar módulos.

    Ler mais

    Tempo de leitura: 6 minutos
    16/08/2026
    Portátil con gráficos de rendimiento que representa análisis de perfiles con pstats en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pstats en Python: analiza perfiles

    Aprende pstats en Python para ordenar, filtrar, combinar e interpretar perfiles de cProfile, callers, callees y tiempos acumulados.

    Ler mais

    Tempo de leitura: 5 minutos
    15/08/2026
    Portátil con código que representa ejemplos ejecutables probados con doctest en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    doctest en Python: prueba ejemplos

    Aprende doctest en Python para ejecutar ejemplos en docstrings y archivos, normalizar salidas e integrar documentación con CI.

    Ler mais

    Tempo de leitura: 5 minutos
    15/08/2026
    Código en pantalla que representa navegación de clases y funciones con pyclbr en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pyclbr en Python: inspecciona módulos

    Aprende pyclbr en Python para listar clases, funciones, métodos y definiciones anidadas sin importar ni ejecutar el módulo.

    Ler mais

    Tempo de leitura: 5 minutos
    15/08/2026
    Monitor con código binario que representa instrucciones opcode del bytecode de Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    opcode en Python: explora el bytecode

    Aprende opcode en Python para mapear instrucciones de bytecode, argumentos, saltos, caches y efectos de pila mediante dis.

    Ler mais

    Tempo de leitura: 5 minutos
    15/08/2026
    Desarrollador investigando consumo de memoria con tracemalloc en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tracemalloc en Python: detecta fugas

    Usa tracemalloc en Python para comparar snapshots, localizar crecimiento de memoria e investigar fugas en aplicaciones.

    Ler mais

    Tempo de leitura: 6 minutos
    15/08/2026