ProgramaciónDesarrollador Backend

Explique cómo funciona la gestión de memoria en Python, incluyendo el recolector de basura. ¿Qué son las referencias cíclicas y cómo las combate Python?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

En Python, la memoria se gestiona automáticamente: cuando se crea un objeto, se asigna memoria, y cuando ningún otro objeto se refiere a él, la memoria se libera. La estrategia principal es el conteo de referencias: cada objeto tiene un contador de referencias asociado, cuando este llega a cero, el objeto se elimina.

Sin embargo, pueden existir referencias cíclicas, donde los objetos se refieren entre sí, y su contador de referencias nunca baja a cero, incluso si las referencias externas han sido eliminadas.

Para combatir esto, Python (CPython) tiene un recolector de basura (garbage collector, GC) que detecta ciclos de objetos que no son accesibles desde las raíces y los elimina. El recolector de basura se puede gestionar desde el módulo gc.

Ejemplo de un ciclo:

class Node: def __init__(self): self.ref = None n1 = Node() n2 = Node() n1.ref = n2 n2.ref = n1 del n1, n2 # ¡los objetos aún viven debido a la referencia cíclica!

Pregunta engañosa

Pregunta: "Si se llama a del obj, la memoria siempre se liberará de inmediato. ¿Es esto cierto?"

Respuesta: ¡No! La operación del solo elimina una referencia al objeto. Si hay otras referencias (ya sean explícitas o cíclicas) el objeto no podrá ser eliminado hasta que el contador de referencias llegue a cero y/o el GC no elimine los ciclos. Ejemplo:

import gc class A: pass x = A() y = x del x # ¡y tiene una referencia restante, el objeto sigue vivo! del y # solo ahora el objeto puede ser eliminado

Ejemplos de errores reales debido a la falta de conocimiento sobre los matices del tema


Historia

En un sistema de procesamiento de grandes archivos se mantenían en memoria objetos relacionados. Después de eliminar las referencias externas, la memoria aún no se liberaba. La razón — referencias cíclicas que no se limpiaban de inmediato y, a veces, no se limpiaban del todo debido a la existencia del destructor __del__.


Historia

En un proceso de servidor de larga duración, a menudo se creaban grandes estructuras temporales con gráficos cíclicos. Los desarrolladores no desactivaron la salida de depuración del GC, lo que provocó pausas raras pero notables en segundo plano. Se diagnosticaron como "caídas de rendimiento". Resultó que la culpable era la frecuente activación del recolector de basura.


Historia

Al portar un gran proyecto a PyPy (un intérprete alternativo), el código antiguo confiaba en el comportamiento específico de CPython de limpieza instantánea de memoria a través del conteo de referencias; en PyPy, los objetos no se eliminaban y limpiaban de inmediato, sino a "petición" del GC, lo que llevó a un comportamiento impredecible con archivos abiertos y conexiones de red.