Gestión de memoria en Swift: cómo funciona ARC y el recolector de basura

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué Swift no utiliza un recolector de basura tradicional?

\n

Si llegaste al mundo de Swift desde Python o Java, seguramente te sorprendió que este lenguaje no tenga un recolector de basura (Garbage Collector) clásico. En su lugar, Apple implementó el mecanismo Automatic Reference Counting (ARC) — conteo automático de referencias. Y esto no es un capricho: en los dispositivos móviles, cada ciclo del procesador y cada byte de memoria cuentan. El GC tradicional «congela» la aplicación durante la recolección, lo que para iOS, con su exigencia de animaciones fluidas (60 FPS), sería una catástrofe.

\n

En este artículo analizaremos cómo funciona realmente la gestión de memoria en Swift, dónde se esconden los problemas con las referencias cíclicas y cómo escribir código que no «se fugue» a ninguna parte.

\n\n

ARC: ¿cómo funciona bajo el capó?

\n

ARC no es un recolector de basura en el sentido tradicional. Funciona en la etapa de compilación: el compilador inserta instrucciones retain y release en los lugares adecuados. Pero hay un detalle: ARC no sabe cómo manejar las referencias cíclicas (retain cycles). Si dos objetos se mantienen mutuamente con referencias fuertes, su contador de referencias nunca llegará a cero — la memoria se fuga.

\n\n

Ejemplo: una clase simple y conteo de referencias

\n
class Person {\n    let name: String\n    init(name: String) {\n        self.name = name\n        print("\\(name) apareció en la memoria")\n    }\n    deinit {\n        print("\\(name) desapareció de la memoria")\n    }\n}\n\nvar person1: Person? = Person(name: "Alicia") // retain count = 1\nvar person2 = person1                        // retain count = 2\nperson1 = nil                                // retain count = 1\nperson2 = nil                                // retain count = 0 → deinit\n
\n

En la consola verás: «Alicia apareció en la memoria» y después de un tiempo — «Alicia desapareció de la memoria». Todo correcto.

\n\n

Referencias cíclicas: el principal enemigo de la memoria

\n

Imagina: tienes un User y un Account. El usuario tiene una cuenta, y la cuenta conoce a su propietario. Si ambas propiedades son referencias fuertes, se forma un círculo vicioso:

\n\n
class User {\n    let name: String\n    var account: Account?\n    init(name: String) { self.name = name }\n    deinit { print("User \\(name) eliminado") }\n}\n\nclass Account {\n    let number: String\n    var owner: User?\n    init(number: String) { self.number = number }\n    deinit { print("Account \\(number) eliminado") }\n}\n\nvar user: User? = User(name: "Boris")\nvar account: Account? = Account(number: "12345")\nuser?.account = account\naccount?.owner = user\n\nuser = nil   // ¡User no se elimina! account?.owner todavía mantiene la referencia\naccount = nil // ¡Account no se elimina! user?.account mantiene la referencia\n// ¡Fuga de memoria!\n
\n

En la consola no aparecerá ningún mensaje deinit. Los objetos quedan en la memoria para siempre. Esto es un retain cycle — un problema clásico de gestión de memoria en Swift.

\n\n

¿Cómo solucionarlo? Weak y unowned

\n

La solución es hacer que una de las referencias sea débil (weak) o sin dueño (unowned). La diferencia:

\n
    \n
  • weak — siempre es opcional, se convierte automáticamente en nil cuando el objeto se elimina. Seguro.
  • \n
  • unowned — no es opcional, asume que el objeto vive más tiempo. Si se accede a un objeto eliminado — crash.
  • \n
\n\n
class Account {\n    let number: String\n    weak var owner: User?  // ← referencia débil\n    init(number: String) { self.number = number }\n    deinit { print("Account \\(number) eliminado") }\n}\n// Ahora user = nil liberará a User, y account?.owner se convertirá en nil\n
\n\n

Recolector de basura vs ARC: ¿cuál es más rápido?

\n

Seamos honestos: ARC no es un «recolector de basura» en el sentido clásico. Un GC real (como en Java, Go o Python) funciona en tiempo de ejecución: escanea periódicamente el heap, encuentra objetos inalcanzables y los libera. Esto requiere pausas (stop-the-world).

\n

ARC, en cambio, es está

Blogs

Book Recommendations