Dalvik: what it is, virtual machine and how it works

Author: IT Sectr Published: 2026-04-16 Reading time: 9 min

The Dalvik virtual machine was a key component of the Android operating system, responsible for running applications up to version 4.4 KitKat. Developed by Dan Bornstein, this register-based VM replaced the standard JVM concept and made it possible to optimize application launch on mobile devices with limited RAM. According to Google, 2024, Dalvik ensured application compatibility through JIT compilation, converting DEX bytecode into machine instructions directly during execution.

Key Takeaways

  • Dalvik is a virtual machine with a register-based architecture, optimized for Android.
  • Unlike JVM, Dalvik executes DEX bytecode, specially compressed for mobile devices.
  • JIT compilation converts part of DEX code into machine code directly while the application is running.
  • Starting with Android 5.0, Dalvik was replaced by ART with ahead-of-time AOT compilation.
  • Understanding Dalvik is necessary for supporting older Android versions and analyzing backward compatibility.

What is Dalvik?

Dalvik is a virtual machine with a register-based architecture, created specifically for the Android platform. Development began in 2005 by Dan Bornstein's company, and in 2007 the project was acquired by Google. The first commercial version of Dalvik appeared with the release of Android 1.0 in 2008.

Unlike the standard Java Virtual Machine (JVM), Dalvik does not execute Java bytecode. The Java compiler converts source code into class files, and then the dx utility translates them into the Dalvik Executable (DEX) format. This format is more compact than class files: a 10 MB application in class format takes approximately 6–7 MB in DEX.

History of Creation

Dan Bornstein wrote Dalvik as a project for operating systems with limited resources. The name was taken from the Icelandic village of Dalvík. Google chose Dalvik over JVM due to licensing restrictions and the need for deep optimization for mobile processors with ARM architecture. The system quickly gained popularity: by 2012, more than 500 million Android devices were running Dalvik.

Role in the Android Ecosystem

Each Android application runs in a separate process with its own instance of the Dalvik VM. This ensures data isolation and protection against malicious code at the operating system level. This approach combines the advantages of virtualization with the Linux sandbox — malware in one application cannot affect neighboring processes.

Dalvik Architecture: Register Machine and DEX

The register-based architecture of Dalvik fundamentally differs from the stack-based architecture of JVM. Instead of operations on the stack top, Dalvik operates with registers — virtual cells inside the VM. Each instruction contains the addresses of operand registers, which reduces the number of instructions per operation.

The JVM stack machine uses instructions like push, pop, and add — adding two numbers requires three instructions. Dalvik solves the same task with one add-int instruction with three registers. According to the Android Open Source Project, the register-based DEX architecture reduces bytecode size by an average of 30% compared to the stack-based class format.

DEX Format

A DEX file (Dalvik Executable) contains a compressed representation of all application classes. The file header includes a checksum, section sizes, and offsets. The main sections are pools of strings, types, method prototypes, fields, and the bytecode itself. A single DEX file can store up to 65,536 methods (the limitation was lifted with the introduction of multi-dex in Android 5.0).

The dx utility, included in Android SDK Build Tools, is used to convert class files to DEX. Example command: dx --dex --output=classes.dex myapp.jar. Modern projects use D8, the successor to dx with improved optimization and support for Java 8+ features.

bash
# Converting JAR to DEX using dx
dx --dex --output=classes.dex myapp.jar

# Modern version via D8
d8 --lib android.jar --output dex/ myapp.jar

Zygote: Framework Preloading

The Zygote process is a crucial element of the Dalvik architecture. When the system starts, Zygote loads all Android SDK classes, opens shared libraries, and creates a pool of preloaded resources. When a user opens an application, the system forks the Zygote process, creating a new Dalvik VM instance with an already initialized framework. This reduces application launch time from ~2–3 seconds to 300–500 milliseconds.

JIT Compilation in Dalvik

JIT (Just-In-Time) is a technology for compiling bytecode into machine instructions directly during application execution. In Dalvik, the JIT compiler analyzes the executing DEX code, identifies frequently used (hot) methods, and compiles them into native code for the CPU.

The choice of JIT over full Ahead-Of-Time (AOT) compilation in early Android versions was deliberate. Mobile devices had limited flash storage (4–16 GB) — pre-compiling all applications would have taken up significant space. Additionally, ROM memory in early devices was slower than RAM, and reading pre-compiled code could reduce performance.

JIT Compilation Process

When an application starts, Dalvik begins interpreting DEX bytecode. A special profiler tracks which methods are called most frequently. After exceeding a threshold (typically ~200 calls), the JIT compiler converts the method into machine code and caches it in RAM. Subsequent calls use the already compiled version without recompilation.

java
// Example of a hot method that JIT will compile
public class Calculator {
    public int sumArray(int[] arr) {
        int total = 0;
        for (int i = 0; i < arr.length; i++) {
            total += arr[i];
        }
        return total;
    }
}

JIT Performance

According to Google I/O 2013, the introduction of JIT in Android 2.2 Froyo accelerated application execution by an average of 2–5 times compared to pure interpretation. However, JIT adds latency on first launch: an application needs 3 to 10 seconds to warm up and compile hot methods. After warm-up, performance stabilizes at a level close to native code.

Dalvik vs JVM: Key Differences

Dalvik differs from JVM in several fundamental ways. First — architecture: JVM is stack-based, Dalvik is register-based. Second — bytecode format: JVM uses class files, Dalvik uses DEX. Third — memory management: Dalvik is optimized for the limited RAM of mobile devices.

Both approaches have their strengths. The stack-based JVM requires less space for storing instructions — each instruction is shorter because operands are implicitly taken from the stack. The register-based Dalvik executes fewer instructions per operation, which saves CPU time and reduces power consumption. For battery-powered mobile devices, this is critical.

ParameterDalvikJVM
ArchitectureRegister-basedStack-based
BytecodeDEXclass
CompilationJIT (Android 2.2+)JIT / AOT
OptimizationLow power consumptionHigh compatibility
IsolationVia Linux processesVia ClassLoader

Licensing Aspects

The choice of Dalvik over JVM was also driven by licensing. Oracle owns the rights to Java SE and JVM, and Google sought to avoid licensing fees. Creating its own VM with an alternative bytecode format allowed Android to develop independently of Oracle. This dispute turned into a long legal battle, Oracle vs Google (2010–2021), which ended in Google's favor.

DEX Format and the dx Utility

DEX (Dalvik Executable) is a binary format containing the compiled code of an Android application. Each DEX file starts with a header, followed by sections: string constants (string_ids), types (type_ids), method prototypes (proto_ids), fields (field_ids), methods (method_ids), class definitions (class_defs), and a data area.

The dx utility converts Java class files into one or more DEX files. The algorithm includes constant deduplication — identical strings or types are stored once and referenced by index. This significantly reduces the final size. In modern projects, dx has been replaced by D8 (introduced in Android Studio 3.1), which is 2–3 times faster and supports Java 8 desugaring.

java
// Example of decompiled DEX bytecode via dexdump
// Source code: return a + b;
@Ldalvik/annotation/Code;
    registers: 3
    add-int v0, v1, v2
    return v0

Multi-dex: Overcoming the 65536 Limit

The DEX format limitation of 65,536 methods (16-bit index limit) became a serious problem for large applications. The solution came with Android 5.0: multi-dex support allows an application to contain multiple DEX files. The main classes.dex contains entry points, while additional classes2.dex, classes3.dex, and so on contain the rest of the code. Multi-dex configuration is enabled in build.gradle with the line multiDexEnabled true.

Memory Management and Garbage Collection

Garbage collection in Dalvik is implemented as a generational collector with mark-and-sweep. Memory is divided into two main areas: Heap for objects and Stack for primitives and references. When the Heap fills up, Dalvik suspends all threads (STW — Stop-The-World), marks reachable objects, and frees unreachable ones.

Before Android 2.2, Dalvik used a single-threaded collector with pause durations of up to 100–200 ms. Android 2.3 Gingerbread introduced a concurrent collector that reduced typical pauses to 5–10 ms. And Android 4.0 Ice Cream Sandwich added an incremental collector — Concurrent Mark and Sweep (CMS).

Memory Leaks

A typical problem with Dalvik applications is memory leaks through static references to Activity. If a static field holds a reference to Context or View, the garbage collector cannot free the Activity even after the screen is closed. Tools like Eclipse MAT and LeakCanary help detect such leaks: they analyze a Heap dump and show reference chains holding the object.

java
// Example of memory leak through a static reference
public class Utils {
    private static Context context;

    public static void init(Context ctx) {
        context = ctx; // Holds Activity after finish()
    }
}

Dalvik Limitations and the Transition to ART

Despite its success, Dalvik had several drawbacks. JIT compilation required warm-up time — the first seconds of application operation were slower. Additionally, JIT consumed CPU power during compilation, reducing battery life. As mobile device performance grew and built-in storage increased, the need for JIT diminished.

In Android 4.4 KitKat, Google introduced ART (Android Runtime) as an experimental replacement for Dalvik. Starting with Android 5.0 Lollipop, ART became the only runtime environment. The main difference is AOT compilation: instead of compiling during execution, all applications are compiled into machine code during installation. This eliminated warm-up delays and improved energy efficiency.

Backward Compatibility

The transition from Dalvik to ART was transparent for developers: both runtimes execute the same DEX bytecode. Applications compiled for Dalvik run on ART without recompilation — system_server compiles them into native code during installation. The exception is code using reflection to access internal Dalvik VM members: such code could break on ART due to changes in the internal architecture.

Frequently Asked Questions

What is Dalvik in simple terms?

Dalvik is an intermediary program that runs Android applications on a phone. It takes the application code and converts it into commands understandable by the processor, doing this directly while the user is working.

How does Dalvik differ from JVM?

Dalvik uses a register-based architecture and the DEX format, while JVM uses a stack-based architecture and the class format. Dalvik is optimized for mobile devices with limited memory and processing power, whereas JVM is designed for desktop computers and servers.

Why did Google replace Dalvik with ART?

ART provides higher performance through ahead-of-time AOT compilation — the application is compiled once during installation, not every time it starts. This speeds up operation and saves battery compared to Dalvik's JIT approach.

Do old applications work on ART?

Yes, ART is fully backward compatible with Dalvik DEX bytecode. During installation, ART compiles old DEX files into native code. The exception is applications that use reflection to access Dalvik internal mechanisms.

What is a DEX file?

DEX (Dalvik Executable) is an executable file format containing compressed bytecode of an Android application. A single APK can contain multiple DEX files (multi-dex) if the application has more than 65,536 methods.

Summary

  • Dalvik VM is a register-based virtual machine created for Android and used up to version 4.4 KitKat.
  • The DEX format provides compact bytecode storage — 30% smaller than JVM class files.
  • JIT compilation in Dalvik accelerated application execution by 2–5 times compared to pure interpretation.
  • The Zygote process preloads the Android framework, reducing application launch time to 300–500 ms.
  • The 65,536 method limit in a single DEX file is resolved through multi-dex starting with Android 5.0.
  • Garbage collection in Dalvik evolved from single-threaded STW to Concurrent Mark and Sweep.
  • The transition to ART in Android 5.0 eliminated JIT warm-up delays and improved energy efficiency.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also