La máquina virtual Dalvik fue un componente clave del sistema operativo Android, responsable de ejecutar aplicaciones hasta la versión 4.4 KitKat. Desarrollada por Dan Bornstein, esta VM basada en registros reemplazó el concepto de JVM estándar y permitió optimizar el inicio de aplicaciones en dispositivos móviles con RAM limitada. Según Google, 2024, Dalvik garantizaba la compatibilidad de aplicaciones mediante compilación JIT, convirtiendo el bytecode DEX en instrucciones de máquina directamente durante la ejecución.
Puntos clave
Dalvik es una máquina virtual con arquitectura de registros, creada específicamente para la plataforma Android. El desarrollo comenzó en 2005 por la empresa de Dan Bornstein, y en 2007 el proyecto fue adquirido por Google. La primera versión comercial de Dalvik apareció con el lanzamiento de Android 1.0 en 2008.
A diferencia de la Máquina Virtual de Java estándar (JVM), Dalvik no ejecuta bytecode de Java. El compilador de Java convierte el código fuente en archivos class, y luego la utilidad dx los traduce al formato Dalvik Executable (DEX). Este formato es más compacto que los archivos class: una aplicación de 10 MB en formato class ocupa aproximadamente 6–7 MB en DEX.
Dan Bornstein escribió Dalvik como un proyecto para sistemas operativos con recursos limitados. El nombre proviene de la aldea islandesa de Dalvík. Google eligió Dalvik en lugar de JVM debido a restricciones de licencia y la necesidad de optimización profunda para procesadores móviles con arquitectura ARM. El sistema rápidamente ganó popularidad: para 2012, más de 500 millones de dispositivos Android funcionaban con Dalvik.
Cada aplicación de Android se ejecuta en un proceso separado con su propia instancia de la VM Dalvik. Esto garantiza el aislamiento de datos y la protección contra código malicioso a nivel del sistema operativo. Este enfoque combina las ventajas de la virtualización con el sandbox de Linux: el malware en una aplicación no puede afectar a procesos vecinos.
La arquitectura basada en registros de Dalvik difiere fundamentalmente de la arquitectura basada en pila de JVM. En lugar de operaciones en la cima de la pila, Dalvik opera con registros — celdas virtuales dentro de la VM. Cada instrucción contiene las direcciones de los registros operando, lo que reduce el número de instrucciones por operación.
La máquina de pila JVM utiliza instrucciones como push, pop y add — para sumar dos números se requieren tres instrucciones. Dalvik resuelve la misma tarea con una instrucción add-int con tres registros. Según el Android Open Source Project, la arquitectura de registros de DEX reduce el tamaño del bytecode en un promedio del 30% en comparación con el formato de pila class.
Un archivo DEX (Dalvik Executable) contiene una representación comprimida de todas las clases de la aplicación. El encabezado del archivo incluye una suma de verificación, tamaños de sección y desplazamientos. Las secciones principales son los grupos de cadenas, tipos, prototipos de métodos, campos y el propio bytecode. Un solo archivo DEX puede almacenar hasta 65,536 métodos (la limitación se eliminó con la introducción de multi-dex en Android 5.0).
La utilidad dx, incluida en Android SDK Build Tools, se utiliza para convertir archivos class a DEX. Ejemplo de comando: dx --dex --output=classes.dex myapp.jar. Los proyectos modernos usan D8, el sucesor de dx con optimización mejorada y soporte para funciones de Java 8+.
# Conversión de JAR a DEX usando dx
dx --dex --output=classes.dex myapp.jar
# Versión moderna mediante D8
d8 --lib android.jar --output dex/ myapp.jar
El proceso Zygote es un elemento crucial de la arquitectura Dalvik. Cuando el sistema se inicia, Zygote carga todas las clases del SDK de Android, abre bibliotecas compartidas y crea un grupo de recursos precargados. Cuando un usuario abre una aplicación, el sistema bifurca el proceso Zygote (fork), creando una nueva instancia de la VM Dalvik con un framework ya inicializado. Esto reduce el tiempo de inicio de la aplicación de ~2–3 segundos a 300–500 milisegundos.
JIT (Just-In-Time) es una tecnología para compilar bytecode en instrucciones de máquina directamente durante la ejecución de la aplicación. En Dalvik, el compilador JIT analiza el código DEX en ejecución, identifica métodos utilizados con frecuencia (hot) y los compila en código nativo para la CPU.
La elección de JIT en lugar de la compilación Ahead-Of-Time (AOT) completa en las primeras versiones de Android fue deliberada. Los dispositivos móviles tenían almacenamiento flash limitado (4–16 GB) — precompilar todas las aplicaciones habría ocupado un espacio significativo. Adicionalmente, la memoria ROM en los primeros dispositivos era más lenta que la RAM, y leer código precompilado podía reducir el rendimiento.
Cuando una aplicación se inicia, Dalvik comienza a interpretar el bytecode DEX. Un perfilador especial rastrea qué métodos se llaman con más frecuencia. Después de superar un umbral (típicamente ~200 llamadas), el compilador JIT convierte el método en código máquina y lo almacena en caché en la RAM. Las llamadas posteriores utilizan la versión ya compilada sin necesidad de recompilación.
// Ejemplo de un método hot que JIT compilará
public class Calculator {
public int sumArray(int[] arr) {
int total = 0;
for (int i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
}
Según Google I/O 2013, la introducción de JIT en Android 2.2 Froyo aceleró la ejecución de aplicaciones en un promedio de 2–5 veces en comparación con la interpretación pura. Sin embargo, JIT añade latencia en el primer inicio: una aplicación necesita de 3 a 10 segundos para calentar y compilar métodos hot. Después del calentamiento, el rendimiento se estabiliza a un nivel cercano al código nativo.
Dalvik difiere de JVM en varios aspectos fundamentales. Primero — arquitectura: JVM está basada en pila, Dalvik en registros. Segundo — formato de bytecode: JVM usa archivos class, Dalvik usa DEX. Tercero — gestión de memoria: Dalvik está optimizada para la RAM limitada de dispositivos móviles.
Ambos enfoques tienen sus puntos fuertes. La JVM basada en pila requiere menos espacio para almacenar instrucciones — cada instrucción es más corta porque los operandos se toman implícitamente de la pila. Dalvik basada en registros ejecuta menos instrucciones por operación, lo que ahorra tiempo de CPU y reduce el consumo de energía. Para dispositivos móviles con batería, esto es crítico.
| Parámetro | Dalvik | JVM |
|---|---|---|
| Arquitectura | Basada en registros | Basada en pila |
| Bytecode | DEX | class |
| Compilación | JIT (Android 2.2+) | JIT / AOT |
| Optimización | Bajo consumo de energía | Alta compatibilidad |
| Aislamiento | Mediante procesos Linux | Mediante ClassLoader |
La elección de Dalvik sobre JVM también estuvo motivada por las licencias. Oracle posee los derechos de Java SE y JVM, y Google buscaba evitar pagos de licencias. Crear su propia VM con un formato de bytecode alternativo permitió a Android desarrollarse independientemente de Oracle. Esta disputa se convirtió en una larga batalla legal, Oracle vs Google (2010–2021), que terminó a favor de Google.
DEX (Dalvik Executable) es un formato binario que contiene el código compilado de una aplicación Android. Cada archivo DEX comienza con un encabezado, seguido de secciones: constantes de cadena (string_ids), tipos (type_ids), prototipos de métodos (proto_ids), campos (field_ids), métodos (method_ids), definiciones de clases (class_defs) y un área de datos.
La utilidad dx convierte archivos class de Java en uno o más archivos DEX. El algoritmo incluye deduplicación de constantes — las cadenas o tipos idénticos se almacenan una vez y se referencian por índice. Esto reduce significativamente el tamaño final. En proyectos modernos, dx ha sido reemplazado por D8 (introducido en Android Studio 3.1), que es 2–3 veces más rápido y admite desugaring de Java 8.
// Ejemplo de bytecode DEX descompilado mediante dexdump
// Código fuente: return a + b;
@Ldalvik/annotation/Code;
registers: 3
add-int v0, v1, v2
return v0
La limitación del formato DEX de 65,536 métodos (límite de índice de 16 bits) se convirtió en un problema serio para aplicaciones grandes. La solución llegó con Android 5.0: el soporte multi-dex permite que una aplicación contenga múltiples archivos DEX. El archivo principal classes.dex contiene los puntos de entrada, mientras que classes2.dex, classes3.dex adicionales, y así sucesivamente, contienen el resto del código. La configuración multi-dex se habilita en build.gradle con la línea multiDexEnabled true.
La recolección de basura en Dalvik se implementa como un recolector generacional con marcado y barrido (mark-and-sweep). La memoria se divide en dos áreas principales: Heap (montón) para objetos y Stack (pila) para primitivas y referencias. Cuando el Heap se llena, Dalvik suspende todos los hilos (STW — Stop-The-World), marca los objetos alcanzables y libera los inalcanzables.
Antes de Android 2.2, Dalvik usaba un recolector de un solo hilo con duraciones de pausa de hasta 100–200 ms. Android 2.3 Gingerbread introdujo un recolector concurrente que redujo las pausas típicas a 5–10 ms. Y Android 4.0 Ice Cream Sandwich agregó un recolector con limpieza incremental — Concurrent Mark and Sweep (CMS).
Un problema típico de las aplicaciones Dalvik son las fugas de memoria a través de referencias estáticas a Activity. Si un campo estático mantiene una referencia a Context o View, el recolector de basura no puede liberar la Activity incluso después de cerrar la pantalla. Herramientas como Eclipse MAT y LeakCanary ayudan a detectar tales fugas: analizan un volcado del Heap y muestran cadenas de referencias que mantienen el objeto.
// Ejemplo de fuga de memoria a través de una referencia estática
public class Utils {
private static Context context;
public static void init(Context ctx) {
context = ctx; // Mantiene Activity después de finish()
}
}
A pesar de su éxito, Dalvik tenía varios inconvenientes. La compilación JIT requería tiempo de calentamiento — los primeros segundos de funcionamiento de la aplicación eran más lentos. Además, JIT consumía energía de la CPU durante la compilación, reduciendo la duración de la batería. A medida que crecía el rendimiento de los dispositivos móviles y aumentaba el almacenamiento incorporado, la necesidad de JIT disminuyó.
En Android 4.4 KitKat, Google presentó ART (Android Runtime) como reemplazo experimental de Dalvik. A partir de Android 5.0 Lollipop, ART se convirtió en el único entorno de ejecución. La principal diferencia es la compilación AOT: en lugar de compilar durante la ejecución, todas las aplicaciones se compilan en código máquina durante la instalación. Esto eliminó los retrasos de calentamiento y mejoró la eficiencia energética.
La transición de Dalvik a ART fue transparente para los desarrolladores: ambos entornos ejecutan el mismo bytecode DEX. Las aplicaciones compiladas para Dalvik funcionan en ART sin recompilación — system_server las compila en código nativo durante la instalación. La excepción es el código que utiliza reflexión para acceder a miembros internos de la VM Dalvik: dicho código podría romperse en ART debido a cambios en la arquitectura interna.
Preguntas frecuentes
Dalvik es un programa intermediario que ejecuta aplicaciones Android en un teléfono. Toma el código de la aplicación y lo convierte en comandos comprensibles para el procesador, haciéndolo directamente mientras el usuario trabaja.
Dalvik utiliza una arquitectura basada en registros y el formato DEX, mientras que JVM utiliza una arquitectura basada en pila y el formato class. Dalvik está optimizada para dispositivos móviles con memoria y potencia de procesamiento limitadas, mientras que JVM está diseñada para computadoras de escritorio y servidores.
ART proporciona un mayor rendimiento mediante la compilación AOT anticipada — la aplicación se compila una vez durante la instalación, no cada vez que se inicia. Esto acelera el funcionamiento y ahorra batería en comparación con el enfoque JIT de Dalvik.
Sí, ART es completamente compatible con el bytecode DEX de Dalvik. Durante la instalación, ART compila los archivos DEX antiguos en código nativo. La excepción son las aplicaciones que usan reflexión para acceder a mecanismos internos de Dalvik.
DEX (Dalvik Executable) es un formato de archivo ejecutable que contiene bytecode comprimido de una aplicación Android. Un solo APK puede contener múltiples archivos DEX (multi-dex) si la aplicación tiene más de 65,536 métodos.
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