Android from the foundation · Puzzle 2 of 6

ART is what runs your code

Your Kotlin ships as DEX bytecode. ART, inside each app's process, reads it line by line, compiles hot code while it runs, and the system compiles more of it ahead of time later.

The problem

In puzzle 1, each app became its own house. But what actually runs inside the house? Android runs on many kinds of CPU, yet you upload one APK, and machine code for one CPU won't run on another. So the APK must hold something more general, and someone in the house has to translate it.

See it

DEX code from the APK goes to ART inside your app's process; ART reads it line by line, compiles hot code right away (JIT) and notes it in a profile; dex2oat later compiles from the profile; a Baseline Profile ships that list in the APK APK your app's process ART DEX line by line… JIT hot! profile dex2oat fast Baseline Profile
  1. You ship one APK for every kind of phone, so it can't hold machine code for one CPU. It holds DEX: instructions for Android's runtime, ART, a translator that lives inside each app's process.

    Step 1 of 5
  2. At first, ART reads the DEX line by line (interpreting): it works, but it's slow.

    Step 2 of 5
  3. Code that runs often is "hot". ART compiles it to machine code right now, while the app runs (JIT), and writes it in a notebook: the profile.

    Step 3 of 5
  4. Later, about once a day while the phone is idle and charging, the system's dex2oat tool compiles the profiled code ahead of time (AOT). Next start, it's already fast.

    Step 4 of 5
  5. A Baseline Profile is that notebook written in advance and shipped inside the APK, so the important code is compiled before your first launch.

    Step 5 of 5

The building block

Your Kotlin compiles to DEX bytecode: compact instructions that aren't tied to any CPU. ART (the Android Runtime) runs inside your app's process and turns them into work. Each piece of code can be in one of three states:

  • interpreted: read one instruction at a time (slow, works immediately);
  • JIT-compiled: compiled to machine code now, while the app runs, because it's hot;
  • AOT-compiled: compiled ahead of time, later, by the system's dex2oat tool, using the profile ART wrote.

ART also runs your app's garbage collector, which frees objects you no longer use. That's for another module.

The analogy

A translator lives in your house. The first time, they read your recipe word by word. Recipes you ask for often, they translate on the spot and note in a notebook. Once a day, at night, a professional translates everything in the notebook properly.

Check yourself

Is there one shared ART for all apps on the phone?

Not quite. ART is the translator living in each house, not a central office. Each process has its own, with its own memory.

Right. ART runs inside each app's process, with its own memory and garbage collector.

Your app gets faster a few days after install. Why?

Not quite. No update needed: the same DEX gets compiled better on the phone, from the profile.

Not quite. JIT code lives in memory while the app runs; it's lost when the app stops. What survives is the notebook (profile).

Right. The JIT writes a profile of hot code, and the system's dex2oat later compiles that code ahead of time.

What's the difference between JIT and AOT?

Not quite. Both work on DEX, which Kotlin and Java both compile to.

Not quite. Both happen on the phone. The difference is when, not where.

Right. Both turn DEX into machine code. JIT does it on the spot for hot code; AOT does it later from the profile.

Sources

What you now know

JIT = compile hot code now, while the app runs. AOT = compile it ahead of time, later, from the profile. A Baseline Profile moves "later" to "before the first launch".