DEX (Dalvik Executable) es un formato de bytecode en el que se compila el código fuente de las aplicaciones de Android en Java y Kotlin. Los archivos DEX se ejecutan en la máquina virtual Dalvik (hasta Android 4.4) o en Android Runtime (ART, a partir de Android 5.0). Según Android Open Source Project, 2026, el formato DEX proporciona en promedio un 30% de representación de código más compacta en comparación con el bytecode estándar de JVM.
Puntos clave
DEX (Dalvik Executable) es un formato de bytecode diseñado específicamente para dispositivos móviles Android. A diferencia del bytecode Java estándar (archivos .class), DEX está optimizado para recursos limitados: menos memoria, menor tamaño y carga de clases más rápida.
El código fuente en Java o Kotlin se compila con javac/kotlinc en archivos .class estándar (bytecode Java). Luego, la herramienta d8 (o anteriormente dx) convierte .class en uno o más archivos DEX. Esta conversión no es un simple reempaquetado — d8 realiza optimizaciones: fusiona grupos de constantes, reescribe instrucciones en arquitectura de registros y elimina datos duplicados.
DEX utiliza una arquitectura basada en registros (a diferencia de la JVM basada en pila). Cada método tiene un número fijo de registros (hasta 65536). Las instrucciones DEX son más cortas — en promedio 2 bytes frente a 1–4 bytes en JVM. Esto produce un código más compacto: una aplicación típica se reduce de 10–15 MB de .class a 4–6 MB de .dex.
Un archivo DEX tiene una estructura binaria estrictamente definida. Cada archivo comienza con un encabezado y contiene varias secciones que se referencian entre sí mediante desplazamientos.
| Sección | Propósito |
|---|---|
| header | Encabezado: magic, suma de verificación, firma, tamaños y desplazamientos de secciones |
| string_ids | Tabla de cadenas: nombres de clases, métodos, campos |
| type_ids | Tipos: referencias a identificadores de cadena de tipos |
| proto_ids | Prototipos de métodos: tipo de retorno y parámetros |
| field_ids | Campos de clases: clase, tipo, nombre |
| method_ids | Métodos: clase, prototipo, nombre |
| class_defs | Definiciones de clases: flags, superclase, interfaces, desplazamientos de datos |
| data | Datos reales: código de métodos, anotaciones, información de depuración |
El número mágico de DEX es `dex\n035\0` (versión 035). Otras versiones: 036, 037, 038 (para Android 8.0+). El encabezado tiene un tamaño de 0x70 bytes y contiene una suma de verificación SHA-1 y los desplazamientos de todas las secciones. La validación del encabezado es el primer paso al cargar un DEX en la máquina virtual.
string_ids, type_ids, proto_ids, field_ids, method_ids — son tablas indexadas. En lugar de almacenar nombres completos en el código del método, se utiliza un índice de 4 bytes. Esta es una optimización clave: si una clase se menciona 100 veces, su nombre se almacena una vez en string_ids. dex2oat optimiza aún más estas tablas durante la compilación ART.
El proceso de convertir el código fuente en DEX consta de varias etapas. La cadena de herramientas moderna utiliza el compilador D8, que reemplazó a DX en 2018 con Android Gradle Plugin 3.2.
javac (para Java) o kotlinc (para Kotlin) compilan el código fuente en archivos .class. Cada clase es un archivo .class separado en bytecode Java. En esta etapa se realizan la verificación de tipos, la generación de métodos puente y la inserción de constantes.
D8 toma todos los archivos .class y los transforma a bytecode DEX. D8 realiza varias optimizaciones: elimina argumentos de métodos no utilizados, fusiona grupos de constantes de diferentes archivos .class en un grupo global de DEX y convierte instrucciones de pila JVM en instrucciones de registro Dalvik.
// Código fuente Kotlin
data class User(
val name: String,
val email: String
)
fun greet(user: User): String {
return "Hello, ${user.name}!"
}
Después de la compilación D8, este código se convierte en instrucciones DEX compactas: const-string para cargar cadenas, iget-object para acceder al campo de un objeto, invoke-virtual para llamar a StringBuilder.append.
D8 es 2–3 veces más rápido que DX, genera DEX más compacto (5–10% más pequeño) y optimiza mejor las construcciones específicas de Kotlin (funciones inline, lambdas). DX fue declarado obsoleto en 2018 y eliminado de Android Gradle Plugin 8.0.
La ejecución del código DEX en Android ha pasado por dos etapas: la máquina virtual Dalvik original (Android 2.2–4.4) y Android Runtime ART (Android 5.0+). La diferencia en el enfoque de compilación es fundamental.
Dalvik utilizaba compilación Just-In-Time (JIT): el bytecode DEX se interpretaba y los métodos llamados con frecuencia se compilaban a código nativo sobre la marcha. Ventaja — instalación rápida. Desventaja — inicio más lento y consumo constante de CPU para JIT.
ART (Android Runtime) compila DEX a código nativo durante la instalación de la aplicación mediante dex2oat. Este es un enfoque Ahead-Of-Time (AOT): la instalación es más lenta, pero el inicio es más rápido y el consumo de energía es menor. Desde Android 7.0, ART utiliza un enfoque híbrido — AOT + JIT + Profile Guided Optimization.
La herramienta dex2oat se ejecuta al instalar o actualizar una aplicación. Compila DEX en un archivo ELF con código nativo para la arquitectura del dispositivo. El resultado — archivos .oat y .art en el directorio /data/dalvik-cache/. Google mejora continuamente dex2oat: en Android 14 se añadieron optimizaciones para dispositivos plegables.
El límite de 65536 métodos por archivo DEX es un legado de la arquitectura Dalvik. El campo method_ids en el encabezado DEX ocupa 4 bytes, lo que da un máximo de 2^16 = 65536 referencias únicas. Las aplicaciones modernas con Google Play Services, Firebase y otros SDK superan fácilmente este límite.
Multidex es un mecanismo para dividir el código en múltiples archivos DEX. El classes.dex principal contiene los puntos de entrada (clase Application, Activity principal), los demás son classes2.dex, classes3.dex, etc. Al iniciar, las clases de los DEX adicionales se cargan mediante DexClassLoader.
// build.gradle.kts — habilitación de multidex
android {
defaultConfig {
multiDexEnabled = true
}
}
// Clase Application con soporte multidex
class MyApp : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
La carga de DEX adicionales durante el inicio de la aplicación puede causar ANR (Application Not Responding) en dispositivos con Android anterior a 5.0. Recomendación — usar multidex solo cuando sea necesario y minimizar las dependencias para no superar el límite.
La optimización de DEX es un paso estándar en la compilación de una aplicación Android de lanzamiento. Las herramientas R8 y ProGuard reducen el tamaño del DEX, ofuscan el código y eliminan clases no utilizadas.
R8 es el sucesor de ProGuard, integrado en Android Gradle Plugin desde 2019. R8 realiza la minimización, ofuscación y optimización en una sola pasada, mientras que ProGuard requería dos etapas: ProGuard → D8. ProGuard aún tiene soporte, pero Google recomienda R8 para proyectos nuevos.
R8 elimina clases, métodos y campos no utilizados, los renombra con nombres cortos (a, b, c), incorpora funciones inline y elimina código muerto. El resultado — el DEX se reduce en un 20–40% sin pérdida de funcionalidad.
La configuración de R8 se especifica en el archivo proguard-rules.pro. El desarrollador puede indicar qué clases no se pueden renombrar (por ejemplo, para reflexión o serialización Gson). Firebase y otros SDK proporcionan sus propias reglas en sus dependencias.
DEX se puede descompilar de vuelta a código Java. Esta es una cuestión clave de seguridad en las aplicaciones Android: sin ofuscación, el código se restaura a un nivel cercano al original.
JADX es el descompilador de DEX a Java más popular. Restaura nombres de clases, métodos, campos y la mayor parte de la lógica. apktool descompila DEX a código smali (ensamblador Dalvik) — una representación de bajo nivel cercana a las instrucciones originales. Bytecode Viewer combina múltiples descompiladores en una interfaz.
La ofuscación con R8/ProGuard es la primera línea de defensa: los nombres de clases y métodos se vuelven ilegibles. DexGuard es una herramienta comercial con métodos adicionales: cifrado de cadenas, verificación de integridad, anti-manipulación. La ofuscación del flujo de control (O-LLVM) cambia la estructura del código manteniendo su funcionalidad, haciendo el análisis mucho más difícil.
Preguntas frecuentes
DEX utiliza una arquitectura basada en registros en lugar de la JVM basada en pila, tiene un formato más compacto (30% más pequeño), fusiona todos los .class en un solo archivo con un grupo de constantes único y utiliza índices de 16 bits en lugar de 8 bits.
Smali es un ensamblador de bytecode DEX. Cada instrucción DEX tiene una representación textual en formato smali. La herramienta baksmali convierte DEX a smali (desensamblado), y smali ensambla smali de vuelta a DEX.
La tarea Gradle countMethods o el plugin dex-method-counts muestran la cantidad de métodos en cada archivo DEX. El comando adb shell con dumpsys también muestra estadísticas de los DEX cargados para las aplicaciones instaladas.
Sí, en dispositivos con Android anterior a 8.0, múltiples DEX ralentizan el inicio de la aplicación porque cada archivo adicional se carga por separado. En ART con Android 8.0+, la diferencia es mínima gracias a la compilación dex2oat en un solo archivo .oat.
Sí, existen proyectos como dexplorer e implementaciones JVM compatibles con Android que pueden ejecutar bytecode DEX fuera de Android. Sin embargo, la mayoría de los archivos DEX utilizan la API de Android, lo que los hace inadecuados para ejecutarse en una JVM estándar.
Resumen
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.
Lea también