OutOfMemoryError en el desarrollo de aplicaciones: qué es, causas y métodos de prevención

Autor: IT Sectr Publicado: 2026-03-29 Tiempo de lectura: 9 min

OutOfMemoryError es una excepción fatal que ocurre cuando la Máquina Virtual de Java (JVM) o Android Runtime (ART) no puede asignar memoria para un nuevo objeto debido a la falta de espacio en el Heap. Según Square Engineering, el 70% de los OutOfMemoryError en aplicaciones móviles son causados por fugas de memoria, no por la superación real del límite. Comprender las causas de OOM es clave para la estabilidad de la aplicación.

Puntos Clave

  • OutOfMemoryError — una excepción cuando no hay suficiente Heap para crear un nuevo objeto
  • Heap — el área de memoria donde viven todos los objetos Java/Kotlin
  • Bitmap — el principal consumidor de Heap en Android, una fuente típica de OOM
  • Heap Dump — una instantánea del Heap para analizar quién ocupa cuánta memoria
  • Tratamiento de OOM requiere corregir fugas y optimizar el consumo de memoria

¿Qué es OutOfMemoryError?

OutOfMemoryError (OOM) es una excepción de la familia VirtualMachineError en Java/Kotlin que indica la imposibilidad de asignar memoria para un nuevo objeto. A diferencia de las excepciones verificadas, OOM es un Error y no requiere manejo mediante catch — aunque técnicamente se puede capturar. Después de que ocurre un OOM, la aplicación suele estar en un estado inestable y se recomienda terminarla.

En Android, cada aplicación tiene un límite de Heap establecido por el fabricante del dispositivo. Para los smartphones modernos con 6+ GB de RAM, el límite es de 256–512 MB, para dispositivos económicos — 128–192 MB. Cuando el volumen total de todos los objetos vivos supera este límite, ART lanza OutOfMemoryError.

Es importante entender: OOM no siempre significa que el dispositivo se haya quedado sin memoria física. Significa que la aplicación ha agotado su límite de Heap establecido por el sistema. Otras aplicaciones pueden tener memoria libre, pero su aplicación no puede usarla debido al aislamiento de procesos en Android.

Causas Principales de OutOfMemoryError

Cinco escenarios conducen regularmente a OOM en aplicaciones móviles. Cada escenario está asociado con un tipo de dato u operación específica.

Bitmap Sin Escalado

Bitmap es el principal consumidor de memoria en aplicaciones Android. Cargar una imagen FullHD (1920 × 1080) en tamaño original ocupa 8.3 MB en formato ARGB_8888. Si hay 50 imágenes así en un RecyclerView, son 415 MB, superando el Heap de cualquier dispositivo. Cargar imágenes sin inSampleSize garantiza OOM en dispositivos débiles.

Use Glide o Coil para el escalado automático. Estas bibliotecas cargan imágenes con un tamaño que coincide con la View, no con la resolución original. Para uso directo de BitmapFactory.Options, aplique inSampleSize: calcúlelo como una potencia de dos para que el tamaño final no supere 2048 × 2048 píxeles. Adicionalmente, use RGB_565 en lugar de ARGB_8888 para imágenes sin transparencia — esto reduce a la mitad el consumo de memoria.

kotlin
fun loadScaledBitmap(path: String, reqWidth: Int): Bitmap? {
    val opts = BitmapFactory.Options().apply {
        inJustDecodeBounds = true
    }
    BitmapFactory.decodeFile(path, opts)
    opts.inSampleSize = calculateSampleSize(opts.outWidth, reqWidth)
    opts.inJustDecodeBounds = false
    return BitmapFactory.decodeFile(path, opts)
}

Fugas de Memoria (Acumulación)

Una sola fuga de unos pocos KB no causará OOM. Pero docenas de fugas en cada pantalla se acumulan: cada transición de pantalla añade una fuga, el GC no puede liberar objetos y el Heap se llena. Un patrón típico: el usuario abre y cierra la pantalla de perfil 20 veces → el Heap crece 200 MB → la aplicación falla con OOM.

Instale LeakCanary en el proyecto para la detección automática de fugas. Mostrará cada objeto filtrado con un stack trace exacto. Después de corregir todas las fugas, el consumo de Heap se vuelve estable: al cerrar una pantalla, la memoria regresa al nivel base.

Archivos Grandes en Memoria

Cargar archivos completos en byte[] es un camino directo a OOM. Un archivo JSON de 50 MB durante el análisis creará una cadena del mismo tamaño más un modelo DOM. Archivos de video cargados en memoria, búferes de audio y grandes conjuntos de datos protobuf — todos pueden exceder el límite de Heap en una sola operación.

Procese datos grandes usando flujos: InputStream con un búfer de 4–8 KB, analizador JSON en streaming (Jackson o Gson con JsonReader), MediaCodec para video. Nunca llame a File.readBytes() en archivos de más del 10% del Heap disponible.

Creación de Muchos Objetos en un Bucle

La creación intensiva de objetos en un bucle sin GC intermedio puede llevar a OOM, especialmente en dispositivos con Heap pequeño. Ejemplo: generar 100,000 objetos en un for-loop que no caben en el Heap antes de que el GC pueda recolectarlos. Esto es más común en juegos y editores gráficos.

Use Object Pool para objetos que se crean y destruyen en masa. Para datos numéricos, use primitivos (FloatArray en lugar de List<Float>). RecyclerView con ViewHolder Pool resuelve este problema para componentes de UI.

Fragmentación del Heap

La fragmentación es un estado donde hay suficiente memoria libre en total, pero no hay un bloque contiguo para un nuevo objeto. ART compacta el Heap durante el GC, pero no siempre con éxito. Los arrays grandes (Bitmap, byte[]) son los más sensibles a la fragmentación.

ART en Android 8+ usa GC Generacional, que reduce la fragmentación separando objetos jóvenes y viejos. No obstante, evite asignar fragmentos de diferentes tamaños en el mismo grupo — intente usar búferes preasignados de tamaño fijo.

Límites de Heap en Android

El límite de Heap en Android no es una constante — depende del fabricante, el modelo del dispositivo y la versión del SO. Google establece requisitos mínimos a través del Documento de Definición de Compatibilidad (CDD), pero los fabricantes establecen los valores reales.

Categoría de DispositivoHeap TípicolargeHeap
Económico (1–2 GB RAM)128–192 MB256–384 MB
Gama Media (3–4 GB RAM)256–384 MB512 MB
Flagship (6+ GB RAM)384–512 MB768 MB–1 GB
Tabletas (4+ GB RAM)256–512 MB768 MB
Wear OS32–64 MBN/A

Puede solicitar un límite aumentado mediante android:largeHeap="true" en el manifiesto. Úselo con precaución: aumentar el Heap no resuelve el problema de las fugas y puede empeorar la experiencia del usuario si el sistema se ve obligado a matar otras aplicaciones para liberar memoria para la suya. Para Wear OS, el límite de Heap es mínimo — solo 32–64 MB, largeHeap no está disponible aquí, y el ahorro de memoria es doblemente crítico.

Diagnóstico de OutOfMemoryError

El diagnóstico de OOM requiere analizar un Heap Dump y comprender qué objetos consumen memoria. Android Studio proporciona todas las herramientas necesarias.

Paso 1: Capture el momento del OOM. En Android Memory Profiler, haga clic en Record memory allocations y ejecute el escenario que causa el fallo. El Profiler mostrará un pico en las asignaciones antes del OOM. Si el OOM no es reproducible, reduzca el Heap mediante android:smallHeap en la compilación de depuración o use DDMS con invocación manual de GC.

Paso 2: Tome un Heap Dump en el pico de carga (antes del OOM). Abra el Dump en Android Studio: la pestaña Classes está ordenada por Retained Size. Los objetos más grandes son Bitmap, byte[], String. Para cada Bitmap, verifique el tamaño (ancho × alto × 4 bytes) y la ruta de carga mediante Stack Trace.

Paso 3: Analice la cantidad de objetos duplicados. Si ve 200 Fragment o Activity idénticos — eso es una fuga. Si 500 Bitmap con el mismo tamaño — es un problema de caché de imágenes. MAT (Memory Analyzer Tool) proporciona un análisis más profundo con un Dominator Tree que muestra qué objetos retienen el 80% del Heap.

text
// Comando de Heap Dump mediante adb
adb shell am dumpheap com.example.app /data/local/tmp/dump.hprof
adb pull /data/local/tmp/dump.hprof.

Estrategias de Prevención de OOM

Una estrategia integral de prevención de OOM incluye cinco niveles de protección: desde decisiones arquitectónicas hasta monitoreo en producción.

Decisiones Arquitectónicas

ViewModel + Repository separa los datos de la UI y evita la retención de View al rotar la pantalla. ViewModel sobrevive a la Activity, sus datos no se pierden y la View se puede recrear sin duplicar datos en memoria. Use StateFlow en lugar de LiveData para la gestión explícita de estados.

Gestión de Bitmap e Imágenes

Glide es una biblioteca obligatoria para trabajar con imágenes. Escala, almacena en caché (disco + memoria) y recicla Bitmap automáticamente. Configure diskCacheStrategy y skipMemoryCache para listas grandes. Para imágenes animadas, use Glide con GIF/WebP — ocupan menos memoria que una secuencia de Bitmaps.

Monitoreo en Producción

Firebase Performance Monitoring rastrea el consumo de memoria en tiempo real. Establezca una alerta cuando el uso del Heap supere el 80% del límite — es una señal para investigar. Crashlytics recopila OOM como una excepción y muestra el último estado del Heap antes del fallo. Para Android 11+, use ApplicationExitInfo para detectar terminaciones por OOM.

Pruebas en Dispositivos Débiles

Asegúrese de probar la aplicación en dispositivos con Heap mínimo (128–192 MB). Un emulador con pantalla pequeña y Heap pequeño emula un dispositivo económico. Si la aplicación funciona en dicho dispositivo, no habrá problemas de OOM en los flagships. Use Firebase Test Lab con dispositivos reales de diferentes categorías de precio.

kotlin
// Comprobación del Heap disponible antes de una operación pesada
fun canAllocate(requiredBytes: Long): Boolean {
    val runtime = Runtime.getRuntime()
    val free = runtime.freeMemory()
    return free > requiredBytes * 2 // 50% de margen
}

Preguntas Frecuentes

¿Se puede capturar OutOfMemoryError con try-catch?

Técnicamente sí, pero no se recomienda. Después de OOM, la aplicación está en un estado inestable: las nuevas asignaciones pueden fallar y algunos objetos pueden estar parcialmente creados. La única acción razonable en catch es registrar y reiniciar la Activity.

¿Por qué OOM no ocurre en todos los dispositivos?

El límite de Heap varía entre dispositivos. Una operación que requiere 300 MB fallará en un dispositivo con límite de 192 MB pero tendrá éxito en un flagship con 512 MB. Pruebe en dispositivos con especificaciones mínimas para detectar escenarios de OOM.

¿Cómo afecta largeHeap al rendimiento?

largeHeap aumenta el límite pero no acelera la aplicación. Las pausas del GC se vuelven más largas ya que recolectar un Heap grande lleva más tiempo. El sistema puede matar aplicaciones en segundo plano para proporcionar memoria. Use largeHeap solo para aplicaciones que objetivamente necesitan mucha memoria (cámaras, editores).

¿En qué se diferencia OOM de una muerte del sistema?

OOM es una excepción dentro de una aplicación cuando el Heap es insuficiente. La muerte del sistema (Low Memory Killer) es una decisión del kernel de Linux de matar un proceso para liberar memoria para otras aplicaciones. En una muerte del sistema, la aplicación no recibe una excepción — el proceso simplemente termina.

¿Cuánta memoria consume realmente un Bitmap?

La fórmula: ancho × alto × bytesPerPixel. ARGB_8888 = 4 B/píxel, RGB_565 = 2 B/píxel. Un Bitmap FullHD (1920 × 1080) en ARGB_8888 = 8.3 MB. Un Bitmap 4K (3840 × 2160) = 33 MB. Siempre escale las imágenes al tamaño necesario para su visualización en la pantalla.

Resumen

  • OutOfMemoryError — una excepción fatal cuando se agota el límite de Heap de la aplicación
  • Bitmap sin escalado — el principal culpable de OOM en aplicaciones móviles
  • Fugas de memoria causan el 70% de OOM mediante la acumulación de objetos en cada transición
  • Límite de Heap varía de 128 MB en dispositivos económicos a 512 MB en flagships
  • Heap Dump con análisis de Retained Size — la herramienta principal para diagnosticar OOM
  • Glide o Coil son obligatorios para trabajar con imágenes de cualquier tamaño
  • Pruebas en dispositivos con Heap mínimo son imprescindibles para todos los proyectos

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