Congelaciones en desarrollo — esencia, causas y prevención

Autor: IT Sectr Publicado: 2026-07-28 Tiempo de lectura: 9 min

Congelación (bloqueo) es un estado en el que una aplicación móvil deja de responder a cualquier acción del usuario durante un período prolongado. A diferencia de los lags (ralentización) y los glitches (comportamiento incorrecto), la congelación bloquea completamente la UI: los toques no se procesan, la animación se detiene, la pantalla se “congela”. La causa es el bloqueo del hilo principal por una operación síncrona, un deadlock en código multihilo o una recolección de basura anormalmente larga. Según la Documentación de Apple Main Thread Checker, más del 40% de los informes de crash en iOS están relacionados con el bloqueo del hilo principal. En Android, una situación similar provoca ANR, el diálogo del sistema “La aplicación no responde”.

Puntos clave

  • Congelación — bloqueo completo de la UI durante un período prolongado (segundos y decenas de segundos), diferente de los lags y glitches
  • Causas principales — bloqueo del hilo principal por E/S, deadlock entre hilos, bucle infinito y fuga de memoria con GC largo
  • Diagnóstico incluye Main Thread Checker en iOS, registros ANR /data/anr/traces.txt en Android y análisis de volcados de hilos
  • Eliminación — descargar todas las operaciones potencialmente largas a hilos en segundo plano, usar Structured Concurrency y evitar synchronized en el hilo de UI
  • Prevención — StrictMode, Main Thread Checker en esquema Debug, análisis estático para deadlock y pruebas periódicas midiendo el tiempo de respuesta

Qué es una congelación en desarrollo móvil

Congelación (bloqueo) en una aplicación móvil es un estado en el que la aplicación deja de procesar eventos de entrada y actualizar la interfaz durante varios segundos o más. Técnicamente, esto significa que el hilo principal está bloqueado y no puede ejecutar la siguiente iteración del bucle de ejecución.

Diferencia entre congelación, lag y ANR

Un lag es un retraso de hasta 500 ms en el que el usuario nota una ralentización pero la aplicación sigue funcionando. Congelación dura desde 1 segundo hasta decenas de segundos. ANR en Android es un caso especial de congelación que duró más de 5 segundos y fue detectado por el sistema. No toda congelación lleva a ANR, pero todo ANR es una congelación documentada por el sistema.

Consecuencias de las congelaciones

En Android, una congelación de más de 5 segundos provoca un diálogo ANR que ofrece cerrar la aplicación. En iOS, el sistema tiene un watchdog: si la aplicación no responde a eventos durante 10–20 segundos, el Watchdog termina el proceso con el código 0x8badf00d (ate bad food). El usuario solo ve que la aplicación se cierra repentinamente a la pantalla de inicio.

Causas de las congelaciones en Android y iOS

Cualquier operación que tarde más de 100 ms y se ejecute en el hilo principal puede causar potencialmente una congelación. Veamos las principales fuentes de bloqueos.

E/S síncrona en el hilo de UI

Leer un archivo grande, una solicitud de red sin asincronía, guardar datos en SharedPreferences con el método síncrono apply seguido de commit — todas estas operaciones bloquean el hilo principal. En Android, leer sincrónicamente un archivo de 10 MB puede tomar 200–500 ms dependiendo de la velocidad de la memoria flash. En iOS, una carga síncrona de URLSession sin completionHandler bloquea la UI durante el tiempo de respuesta del servidor.

Deadlock en código multihilo

Cuando dos hilos esperan recursos retenidos mutuamente, se produce un deadlock. En aplicaciones móviles, un escenario típico es que el hilo A bloquea Lock1 y espera Lock2, mientras que el hilo B bloquea Lock2 y espera Lock1. Ambos hilos se congelan para siempre. Si uno de ellos es el hilo principal, la aplicación se congela completamente.

Bucle infinito o recursión

Un error de lógica — por ejemplo, while(true) sin condición de salida o recursión sin caso base — provoca una ejecución infinita en el hilo principal. Android detecta esto mediante ANR después de 5 segundos, iOS — mediante Stackshot, que captura una pila de llamadas que se repite infinitamente.

  • Android — Cursor sin cerrar, solicitud síncrona con execute() en lugar de enqueue(), FileInputStream.read() en el hilo de UI
  • iOS — performSelectorOnMainThread:withObject:waitUntilDone:YES, lanzar NSURLConnection sendSynchronousRequest, cargar una imagen con dataWithContentsOfURL
  • Multiplataforma — Flutter compute sin un isolate dedicado, React Native NativeModule síncrono

Cómo diagnosticar congelaciones

El diagnóstico de congelaciones requiere herramientas capaces de capturar el estado de todos los hilos en el momento del bloqueo.

Registros ANR en Android

En cada ANR, el sistema Android guarda un archivo /data/anr/traces.txt que contiene un volcado de pila de cada hilo de la aplicación. Analizar este archivo es el método principal de diagnóstico: hay que encontrar el hilo main y ver en qué método se detuvo. Si la pila termina en Thread.sleep, InputStream.read o Lock.lock — la causa está encontrada.

Stackshot en iOS

Xcode puede tomar un Stackshot — una instantánea de las pilas de todos los hilos — cuando la aplicación se congela (señal SIGSTOP). Active “Logging” → “Include Stackshot Logs” en el esquema. En un crash con código 0x8badf00d, extraiga el registro de crash de Devices & Simulators y busque el hilo com.apple.main-thread con la pila bloqueada.

Main Thread Checker en Xcode

Main Thread Checker detecta automáticamente llamadas a UIKit desde hilos en segundo plano mientras la aplicación se ejecuta. Actívalo en el esquema (Diagnostics → Main Thread Checker). Cada advertencia es una causa potencial de congelación, especialmente si ocurre en un closure completionHandler de una solicitud de red.

Ejemplo de detección de bloqueos mediante StrictMode en Android:

kotlin
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
            .detectLeakedSqlLiteObjects()
            .detectLeakedClosableObjects()
            .penaltyLog()
            .build())
        StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyDeath()
            .build())
    }
}

Métodos para eliminar bloqueos de UI

Eliminar las congelaciones comienza con mover todas las operaciones potencialmente largas a hilos en segundo plano. Veamos técnicas específicas para cada plataforma.

Concurrencia estructurada con corrutinas

Kotlin Coroutines con viewModelScope.launch(Dispatchers.IO) garantizan que las operaciones de red o lecturas de base de datos se ejecuten en un hilo en segundo plano. Dispatchers.Main se usa solo para actualizar la UI. Importante: todas las funciones suspend deben estar estructuradas — las corrutinas hijas se cancelan cuando se cancela la padre, evitando fugas de hilos.

Colas asíncronas en iOS

Grand Central Dispatch con DispatchQueue.global(qos: .userInitiated) para tareas en segundo plano y DispatchQueue.main.async para actualizaciones de UI es el patrón estándar. Evite sync() en la cola principal — esto es un deadlock garantizado. Use async/await (Swift 5.5+) para código asíncrono más legible con retorno automático al hilo principal mediante MainActor.

Evitar synchronized en el hilo de UI

Los bloques synchronized en Kotlin y @synchronized en Swift en el hilo principal son peligrosos: si otro hilo ya ha adquirido este bloqueo, el hilo principal se congelará esperando. Use tipos atómicos (AtomicInteger, propiedades atómicas en Swift) o colas seriales en lugar de bloqueos.

Ejemplo de carga asíncrona de datos con corrutinas en Android:

kotlin
class DataViewModel : ViewModel() {
    private val _data = MutableStateFlow<List<Item>>(emptyList())
    val data: StateFlow<List<Item>> = _data.asStateFlow()

    fun loadData() {
        viewModelScope.launch(Dispatchers.IO) {
            val result = fetchFromNetwork()
            _data.emit(result)
        }
    }
}

Prevención de congelaciones en la etapa de desarrollo

Una combinación de herramientas, principios arquitectónicos y procesos de revisión de código ayuda a prevenir sistemáticamente las congelaciones.

StrictMode con penaltyDeath

Configure StrictMode con penaltyDeath para las políticas de hilos — esto provocará un cierre inmediato de la aplicación cuando se detecte una llamada de red o E/S de disco en el hilo principal. El desarrollador no podrá ignorar el problema. En compilaciones de producción, use penaltyLog para recopilar estadísticas sin cierres.

Main Thread Checker en esquema Debug

En iOS, active Main Thread Checker en el esquema Debug y configure CI para ejecutar pruebas con esta opción. Si una prueba contiene una llamada a UIKit desde un hilo en segundo plano — debe fallar. Esta es la única forma fiable de identificar el problema antes de enviar a TestFlight.

Revisión entre pares con verificación de multihilo

Agregue un elemento obligatorio al proceso de revisión de código: verificar que cualquier llamada de red, operación con archivos, acceso a base de datos o cálculo pesado se ejecute en un hilo en segundo plano. Deadlock se puede detectar con analizadores estáticos: Infer de Facebook y Thread Safety Checker de Xcode encuentran bloqueos potenciales antes de la ejecución.

  • Android — StrictMode, Infer, Android Lint Multithread, Kotlin Coroutines con viewModelScope
  • iOS — Main Thread Checker, TSAN (Thread Sanitizer), Xcode Analyze, Swift async/await con MainActor
  • Multiplataforma — Flutter compute isolate, React Native interaction manager con requestAnimationFrame

Preguntas frecuentes

¿Cuál es la diferencia entre congelación y ANR?

ANR (Application Not Responding) es una notificación del sistema Android que aparece cuando el hilo principal se congela durante más de 5 segundos. La congelación es un concepto más amplio: cualquier bloqueo de UI de cualquier duración. iOS no tiene ANR, pero tiene un Watchdog con un tiempo de espera de 10–20 segundos.

¿Cómo leer traces.txt en Android?

El archivo se encuentra en /data/anr/traces.txt. El acceso requiere root o adb shell: ejecute adb shell cat /data/anr/traces.txt \> traces.txt con privilegios de root. En la pila, busque el hilo “main” — el último método llamado indica la causa del bloqueo.

¿Por qué la aplicación se congela en iOS pero no falla?

Si la congelación dura menos de 10 segundos, el Watchdog no se activa y la aplicación simplemente se “bloquea” hasta que se completa la operación bloqueante. El usuario no ve un crash, pero experimenta frustración. Para detectar estos casos, use MetricKit con trazas personalizadas de tiempo de ejecución.

¿Cómo probar una aplicación contra congelaciones?

Use pruebas de UI verificando que la pantalla se abra en < 1 segundo. Agregue a CI la medición del tiempo entre el toque y la aparición de la siguiente pantalla. En Android, use Espresso con IdlingResource para esperar operaciones asíncronas. En iOS, use XCTest con XCTWaiter para verificar el tiempo de carga.

¿Puede SwiftUI causar congelaciones?

SwiftUI por sí mismo no causa congelaciones, pero los cálculos complejos en la propiedad body sí. Si body tarda 500 ms en calcularse debido a operaciones pesadas, la UI se congela. La solución es descargar los cálculos a Task.detached y actualizar @State asíncronamente en el actor principal.

Resumen

  • Congelación — bloqueo completo de la UI durante segundos o decenas de segundos, causado por bloqueo del hilo principal, deadlock o bucle infinito
  • Diagnóstico — /data/anr/traces.txt en Android, Stackshot y Main Thread Checker en iOS
  • Causas principales — E/S síncrona, deadlock entre hilos, recursión infinita, GC largo
  • Eliminación — corrutinas con los dispatchers correctos, async/await con MainActor, descargar todas las operaciones de E/S a hilos en segundo plano
  • Prevención — StrictMode con penaltyDeath, Main Thread Checker, análisis estático para deadlock (Infer, TSAN)
  • En Android congelación > 5 s = ANR; en iOS > 10–20 s = Watchdog crash (0x8badf00d)
  • Recomendación: active Thread Sanitizer en el esquema Debug y configure CI para ejecutar pruebas con TSAN para detectar data races y deadlocks

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también