JIT: qué es la compilación Just-In-Time y cómo funciona

Autor: IT Sectr Publicado: 2026-04-16 Tiempo de lectura: 9 min

JIT (Just-In-Time) es una tecnología de compilación dinámica que convierte el bytecode o la representación intermedia de un programa en instrucciones de máquina directamente durante la ejecución. En Android, el compilador JIT apareció por primera vez en la versión 2.2 Froyo como parte de la máquina virtual Dalvik y aceleró la ejecución de aplicaciones entre 2 y 5 veces. Según Google, 2024, el JIT moderno en ART combina la interpretación con la compilación perfilada de métodos hot.

Puntos clave

  • JIT — compilación Just-In-Time: conversión de código en código máquina directamente mientras el programa se ejecuta.
  • En Dalvik, JIT compilaba métodos hot después de superar el umbral de llamadas (~200 veces).
  • JIT reduce el tiempo de instalación y ocupa menos espacio que la compilación AOT completa.
  • El principal inconveniente es el retraso de calentamiento: los primeros segundos la aplicación funciona más lento.
  • En el ART moderno, JIT se utiliza en modo híbrido con optimización AOT en segundo plano.

¿Qué es la compilación JIT?

Just-In-Time (JIT) es un método de compilación en el que el código fuente o bytecode se convierte en instrucciones de máquina no por adelantado (como con AOT), sino en el momento de la primera llamada a la sección correspondiente del programa. El término “Just-In-Time” significa que la compilación ocurre “justo a tiempo” — inmediatamente antes de la ejecución.

El concepto de JIT existe desde la década de 1960, pero ganó adopción generalizada con la llegada de la Máquina Virtual de Java en 1995. JIT permite combinar la portabilidad del bytecode (escribe una vez — ejecuta en cualquier lugar) con un rendimiento cercano al código nativo. En la JVM HotSpot, el compilador JIT analiza el código ejecutado y compila solo las secciones más críticas, ahorrando tiempo y memoria.

Cómo funciona

El compilador JIT recibe bytecode como entrada, lo interpreta y simultáneamente recopila estadísticas. Cuando una sección de código (método, bucle) se llama con suficiente frecuencia, JIT decide compilarla. El código máquina compilado se almacena en un caché — en llamadas posteriores, se utiliza la versión ya compilada. Esto proporciona aceleración sin tener que compilar todo el programa.

java
// Ejemplo: un método se vuelve hot después de múltiples llamadas
public class HotMethod {
    private int compute(int n) {
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += i * i;
        }
        return sum;
    }
}

// Llamar 500 veces en un bucle — JIT compilará compute
for (int t = 0; t < 500; t++) {
    hot.compute(1000);
}

JIT en Android: Dalvik y ART

En Android, la compilación JIT pasó por tres fases de evolución. La primera fase — Dalvik sin JIT (Android 1.0–2.1): interpretación pura del bytecode DEX. La segunda fase — Dalvik con JIT (Android 2.2–4.4): la introducción del compilador JIT, que aceleró las aplicaciones entre 2 y 5 veces. La tercera fase — ART con JIT híbrido (Android 7.0+): el regreso de JIT en una nueva capacidad.

JIT en Dalvik se implementó como un compilador basado en trazas. Analizaba no métodos individuales, sino cadenas de instrucciones (trazas) que se ejecutan con frecuencia secuencialmente. Esto permitía compilar rutas de ejecución completas, incluyendo múltiples métodos. Este enfoque era efectivo para procesadores móviles con cachés de instrucciones pequeñas, ya que la traza compilada cabía en el caché L1.

JIT en ART moderno

A partir de Android 7.0 Nougat, ART utiliza JIT basado en métodos — compila métodos individuales basándose en perfiles de ejecución. Este JIT funciona significativamente más rápido que Dalvik JIT: el tiempo típico de compilación de un método es de 0.5–1 ms en comparación con 3–5 ms en Dalvik. El código compilado se almacena en un área de memoria separada (caché de código JIT) en lugar del heap de la aplicación, lo que reduce la fragmentación.

ParámetroDalvik JITART JIT
TipoBasado en trazasBasado en métodos
Velocidad de compilación3–5 ms/método0.5–1 ms/método
Umbral de compilación~200 llamadasDinámico
Caché de códigoEn el heap de la aplicaciónCaché de código JIT
PerfiladoInternoArchivos .prof externos

Detección de métodos hot y umbrales de compilación

El mecanismo central de JIT es la detección de métodos hot. Cada llamada a un método incrementa un contador interno. Cuando el contador cruza el umbral, el método se marca como “hot” y se envía a compilación. En Dalvik, el umbral era fijo (~200 llamadas). En ART, los contadores se configuran dinámicamente según los recursos disponibles del dispositivo.

El proceso de compilación incluye varias fases. La primera — análisis de bytecode: JIT examina el flujo de instrucciones y construye un grafo de flujo de datos. La segunda — optimización: inline de métodos pequeños, eliminación de código muerto, plegado de constantes. La tercera — generación de código: conversión del grafo optimizado en instrucciones de máquina para una arquitectura de CPU específica (ARM, ARM64, x86).

java
// Demostración de inlining — JIT integrará el cuerpo del método
public int inlineExample() {
    return square(5);
}

private int square(int x) {
    return x * x;
} // JIT reemplazará la llamada con return 5 * 5;

OSR — Reemplazo en pila (On-Stack Replacement)

Una técnica especial de JIT — On-Stack Replacement (OSR). Si un método contiene un bucle largo que no termina durante cientos de iteraciones, JIT puede compilar el bucle “sobre la marcha” y reemplazar la versión interpretada por la compilada directamente durante la ejecución. OSR es especialmente efectivo para tareas computacionales: renderizado, procesamiento de imágenes, criptografía.

JIT vs AOT: análisis comparativo

JIT y AOT son dos enfoques de compilación con compensaciones opuestas. JIT sacrifica la velocidad del primer inicio por un tamaño de distribución compacto y adaptabilidad. AOT sacrifica el tiempo de instalación y el espacio en disco por el máximo rendimiento desde el primer segundo. Ningún enfoque es absolutamente mejor — la elección depende del escenario.

La ventaja clave de JIT es la optimización adaptativa. JIT puede usar información de perfil no disponible para AOT: tipos exactos de objetos, frecuencia real de llamadas, patrones de ramificación reales. Esto permite aplicar optimizaciones agresivas imposibles con la compilación estática. Por ejemplo, JIT puede desvirtualizar llamadas a métodos si solo se encuentra un tipo de receptor en la práctica.

CriterioJITAOT
Tiempo de instalaciónInstantáneoDepende del tamaño
Primer inicioMás lento (calentamiento)Rápido
Espacio en discoMínimo+15–30%
AdaptabilidadAltaBaja
Uso de CPUPicos durante compilaciónEstable

Cuándo elegir JIT

La compilación JIT es preferible cuando son importantes el despliegue rápido y el ahorro de espacio en disco. En el contexto del desarrollo móvil, JIT es ideal para aplicaciones que se actualizan con frecuencia (pruebas A/B, parches en caliente). JIT también es conveniente durante el desarrollo, cuando el código se reconstruye docenas de veces al día — cada segundo ahorrado en compilación acelera el ciclo de retroalimentación.

Ventajas de la compilación JIT

JIT proporciona a los desarrolladores una serie de ventajas prácticas. La primera — tamaño pequeño del APK. Con el enfoque JIT, solo el bytecode (DEX) se empaqueta en el APK, que ocupa 20–30% menos espacio que el código nativo compilado. Para usuarios con almacenamiento interno limitado, esta es una ventaja significativa.

La segunda ventaja es la adaptación al dispositivo. JIT compila código teniendo en cuenta la arquitectura real de la CPU, la cantidad de RAM y la carga actual. Por ejemplo, en un dispositivo con 2 GB de RAM, JIT puede compilar de forma menos agresiva para ahorrar memoria, mientras que en un flagship con 12 GB puede aplicar todas las optimizaciones posibles. La compilación AOT, por otro lado, fija la decisión en el momento de la instalación.

Independencia de plataforma

El bytecode permanece independiente de la plataforma, lo que simplifica la distribución de aplicaciones. Un solo APK funciona en dispositivos ARM, ARM64 y x86, y JIT genera código nativo para cada arquitectura. El enfoque AOT requeriría incluir múltiples variantes de código nativo en el APK (aumentando el tamaño) o compilar una versión separada para cada arquitectura.

Desventajas y limitaciones de JIT

La principal desventaja de JIT es el retraso de calentamiento. El usuario experimenta ralentizaciones en los primeros segundos de la aplicación mientras JIT compila los métodos hot. En los juegos, esto se manifiesta como tartamudeo en los niveles iniciales. En aplicaciones con animaciones — transiciones bruscas entre pantallas.

La segunda desventaja — consumo de energía. El proceso de compilación carga intensamente la CPU, aumentando el consumo de energía entre un 10–20% durante el período de calentamiento. En dispositivos con batería, esto reduce la autonomía. Es especialmente notable en escenarios con reinicios frecuentes de aplicaciones (multitarea con memoria limitada, donde el sistema descarga y recarga procesos).

Fragmentación del caché

Otro problema — la fragmentación del caché JIT. El código compilado se almacena en un área de memoria continua. Cuando se cargan nuevas clases y se compilan métodos adicionales, el caché se fragmenta, aumentando la sobrecarga de gestión de memoria. En Dalvik, este problema se resolvía con la limpieza periódica del caché; en ART, el caché JIT se asigna por separado del heap y utiliza su propia estrategia de desfragmentación.

Modo híbrido: lo mejor de dos mundos

El enfoque moderno en ART — la compilación híbrida, que combina las fortalezas de JIT y AOT. Durante la instalación de la aplicación, no se realiza compilación — solo verificación de bytecode (verify). Esto garantiza una instalación rápida y un uso mínimo de espacio. Los primeros lanzamientos se ejecutan en modo de interpretación con compilación JIT de métodos hot — el usuario obtiene un rendimiento aceptable sin largos tiempos de espera.

Simultáneamente, un perfilador en segundo plano recopila datos sobre el uso real. Después de 2–3 lanzamientos completos de la aplicación, el perfil alcanza suficiente completitud, y el sistema ejecuta dex2oat para compilar los métodos hot en código nativo. Esta operación se realiza en segundo plano cuando el dispositivo no está cargado (cargando, pantalla apagada). Una vez completada la AOT en segundo plano, la aplicación alcanza un rendimiento comparable a la compilación AOT completa.

bash
# Inicio forzado de compilación en segundo plano
adb shell cmd package compile -m speed-profile -f com.example.app

# Ver estado de compilación
adb shell cmd package dump-profiles com.example.app

Resultados del enfoque híbrido

Según Google I/O 2017, la compilación híbrida redujo el tiempo de instalación de aplicaciones entre un 30–50% en comparación con AOT pura. El espacio ocupado en la partición del sistema disminuyó entre un 20–30%. Al mismo tiempo, el rendimiento después de la compilación en segundo plano coincide con el nivel de AOT completa. El único escenario donde el híbrido es inferior a AOT es el primer inicio inmediatamente después de la instalación: la aplicación funciona en modo JIT y puede ser 10–15% más lenta.

Preguntas frecuentes

¿Qué es la compilación JIT en términos simples?

JIT es una forma de acelerar un programa donde el código se traduce a lenguaje máquina no por adelantado, sino en partes mientras se ejecuta. Las secciones más frecuentes se compilan y almacenan en caché, mientras que las raras permanecen en su forma original.

¿En qué se diferencia JIT de AOT?

JIT compila código durante la ejecución, ahorrando espacio y acelerando la instalación. AOT compila todo el código por adelantado — la aplicación se inicia más rápido pero requiere más espacio en disco y tiempo de instalación.

¿Por qué se eliminó JIT de Android?

JIT no se eliminó — evolucionó. En Android 5.0, Dalvik con JIT fue reemplazado por ART con AOT pura. En Android 7.0, JIT regresó a ART como parte de un sistema híbrido donde trabaja junto con la compilación AOT en segundo plano para un rendimiento óptimo.

¿Cómo afecta JIT al consumo de energía?

JIT aumenta el consumo de energía entre un 10–20% durante el período de calentamiento debido a la carga de la CPU. Una vez completada la compilación de métodos hot, el consumo de energía regresa a niveles normales. El modo híbrido de ART minimiza estos picos mediante la compilación en segundo plano.

¿El calentamiento de JIT es visible para el usuario?

Sí, en escenarios con cálculos intensivos. El usuario puede notar ralentizaciones en los primeros segundos de funcionamiento de la aplicación o al inicio de un juego. En las versiones modernas de Android (8.0+), el modo híbrido minimiza este efecto gracias a la compilación perfilada.

Resumen

  • JIT (Just-In-Time) es una compilación dinámica que convierte bytecode en instrucciones de máquina durante la ejecución.
  • En Android, JIT evolucionó: basado en trazas en Dalvik → AOT completa → JIT+AOT híbrido en ART moderno.
  • Los métodos hot se detectan mediante contadores de llamadas y se compilan al superar el umbral (~200 llamadas).
  • OSR (On-Stack Replacement) permite compilar bucles largos sobre la marcha sin interrumpir la ejecución.
  • Principales ventajas de JIT: tamaño pequeño de APK, instalación rápida y adaptación al dispositivo.
  • Principales desventajas: retraso de calentamiento, consumo máximo de energía y fragmentación del caché.
  • El modo híbrido de ART (Android 7.0+) reduce el tiempo de instalación entre un 30–50% manteniendo un alto rendimiento.

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