Módulo 03: Dart Deep Dive

Garbage Collector

Runtime Memoria

# Garbage Collector en Dart Dart es un lenguaje con gestión automática de memoria. Utiliza un **Garbage Collector (GC)** generacional avanzado para asignar y liberar memoria sin intervención del programador. ## ¿Cómo funciona la Memoria en Dart? La memoria Heap (donde viven los objetos) se divide en dos espacios principales: 1. **Young Space (Espacio Joven)**: Para objetos nuevos y de vida corta. 2. **Old Space (Espacio Viejo)**: Para objetos que sobreviven mucho tiempo. ### 1. Young Space (Scavenger) - **Diseñado para:** Objetos temporales (widgets stateless, variables locales, eventos). - **Algoritmo:** Copying Collector (Cheney's algorithm). - **Velocidad:** Extremadamente rápido. - **Frecuencia:** Muy alta. Cuando creas un objeto, se asigna aquí. Cuando el espacio se llena, el GC: 1. Identifica los objetos "vivos" (referenciados). 2. Los copia a una nueva mitad del espacio. 3. Ignora los objetos muertos (se sobrescriben). **Importante:** En Flutter, los Widgets son inmutables y de vida corta. El Scavenger está optimizado para limpiar miles de widgets por frame sin causar "jank". ### 2. Old Space (Mark-Sweep-Compact) - **Diseñado para:** Objetos persistentes (singletons, datos en caché, estado de la app). - **Algoritmo:** Mark-Sweep y Mark-Compact. - **Velocidad:** Más lento. - **Frecuencia:** Baja. Si un objeto sobrevive a varios ciclos del Scavenger, es "promovido" al Old Space. ## Optimizaciones para Flutter El GC de Dart tiene hooks específicos para Flutter: - **Idle Time Collection:** Si la app está inactiva (no hay animaciones ni toques), el GC aprovecha para limpiar memoria sin afectar el rendimiento. - **Memory Pressure:** Si el sistema operativo avisa que hay poca RAM, el GC se vuelve más agresivo. ## Memory Leaks (Fugas de Memoria) Aunque hay GC, puedes tener fugas de memoria si mantienes referencias a objetos que ya no necesitas. ### Causas Comunes 1. **Listeners no cancelados:** ```dart // ❌ Leak: StreamSubscription nunca se cancela void initState() { someStream.listen((data) => updateUi(data)); } // ✅ Correcto StreamSubscription? _sub; void initState() { _sub = someStream.listen((data) => updateUi(data)); } void dispose() { _sub?.cancel(); super.dispose(); } ``` 2. **Controladores no dispuestos:** - `TextEditingController` - `AnimationController` - `ScrollController` - Siempre llama a `.dispose()`. 3. **Variables estáticas globales:** - Mantienen objetos vivos por siempre. 4. **Closures que capturan `context`:** - Ten cuidado al guardar closures que hacen referencia a un `BuildContext` de un widget que ya no existe. ## Herramientas de Diagnóstico Usa **Dart DevTools** para analizar la memoria: 1. **Memory View:** Ver gráfico de uso de memoria en tiempo real. 2. **Allocation Profile:** Ver cuántos objetos de cada tipo existen. 3. **Heap Snapshot:** Tomar una "foto" de la memoria para buscar leaks. ## Conclusión - Dart usa un GC generacional (Young/Old space). - La creación de objetos de vida corta (Widgets) es muy barata. - Debes liberar recursos manuales (Streams, Controllers) usando `dispose()`. - El GC trabaja con Flutter para minimizar pausas durante animaciones.

Este apartado profundiza en los conceptos clave, proporcionando ejemplos prácticos y mejores prácticas para su aplicación en proyectos reales.

Al comprender estos detalles, podrás diseñar soluciones más robustas, mantenibles y escalables en tus aplicaciones Flutter y Dart.