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

    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026
    Archivos protegidos que representan extracción segura de TAR con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extrae TAR con seguridad

    Aprende tarfile extraction_filter en Python para extraer archivos TAR con validación, seguridad y control de rutas.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python mostrando avisos controlados con catch_warnings
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: captura warnings en pruebas Python

    Aprende catch_warnings en Python para capturar, probar y controlar avisos con filtros específicos y alcance seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python que representa referencias persistentes de pickle
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serializa referencias externas

    Aprende pickle persistent_id en Python para referencias externas estables, validación, seguridad, rendimiento y compatibilidad.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binario que representa buffers y vistas de memoria en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: cuenta valores sin copiar buffers

    Aprende memoryview.count en Python para contar bytes y valores en buffers sin copias, con formatos, límites y buenas prácticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python y anotaciones de tipos
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evita imports circulares en anotaciones

    Aprende annotationlib en Python para inspeccionar anotaciones diferidas, evitar imports circulares y crear herramientas seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026