Android Internals: ART vs DVM deep dive
In the previous article on Android Internals, we learnt how Android OS Starts an application. We mentioned many things such as Bootloader, Kernel, init process, Zygote, DVM and System server.
In this post, we’ll take a look at the runtime environment in Android and how it has changed over the years. More specifically, we’ll be having a comparing ART vs DVM in Android on multiple factors such as installation time, runtime performance and other optimizations such as app size.
But to understand this, let’s first start with some basics such as what is a Virtual Machine? Stack based vs Register Based architecture of VM and comparing JVM vs DVM.
What is a Virtual Machine?
Virtual Machine is an abstraction over the native machine backed by the resources of the native machine. It’s job is to convert language specific code to a format compatible to run on the Virtual Machine. Virtual Machine enables the same code to be run on multiple platform independent of the underlying hardware.
For example the JVM runs java bytecode and produces same output on multiple platforms. Bytecode produced in windows machine will be able to run on a JVM running in UNIX machine.
Note: JVM is not platform independent. It is written in C/C++ and is platform dependent. You’ll always need something to communicate with the underlying architecture.
A virtual machine should be able to carry out all the operations of a physical CPU. These include:
- Compilation of source code into VM specific code.
- Data Structure to contain operands and instructions.
- Instruction Pointer
- A Virtual CPU
We’ll be looking at the two ways of implementing a Virtual Machine:
- Stack Based Architecture.
- Register Based Architecture.
Stack Based Architecture
Stack is a LIFO data structure, which means what comes in last is computed first. If you’ve taken a class on Computer Architecture, you’d be familiar with how arithmetic operations work in case of Stack Based Architecture.
Let’s take an example. Consider the stack given below:
Now, in order to compute the sum of the first two operands, the chain of command would be:
- Pop 20
- Pop 7
- Add 20 + 7
- Push result into stack.
Here are the actual CPU instructions:
- POP 20
- POP 7
Note here that for addition of two integers, we’ve generated 3 lines of code.
Some Advantages of Stack based architecture:
- Shorter lengths of instructions.
- Fast operation as stack pointer immediately points to the next memory location after pop.
- No explicit memory reference required due to stack pointer.
Some Disadvantages of Stack based architecture:
- Size of the program increases.
Register Based Architecture
Register is a small place inside the processor which can hold various types of data such as operands, instruction, memory location etc.
The length of instruction a register can store, depends upon the architecture of the machine. For example: 64 bit machine has registers which can hold 64 bit instructions.
Here is the format of instruction in a MIPS32 register based architecture:
Now, if we were to perform the same addition operation as in Stack Based register, it would look something like this:
- ADD R1, R2, R3
What this instruction essentially means is that, add R2 and R3 and store the result in R1. Notice how we complete the operation with a single instruction. This is the main advantage of Register based architecture over Stack based (which took 3).
On an average, register based architecture has to run 47% less instructions than stack based. But the register code is 25% larger than stack code.
This knowledge of Stack based architecture and Register based architecture is good to have and will come in handy when we’ll talk about ART vs DVM in android as well as JVM vs DVM in the next section.
JVM vs DVM
Java Virtual Machine is a virtual machine capable of running the java bytecode independent of the underlying platform. Java bytecode can be run on any machine capable of running JVM.
Here is the architecture of JVM:
- It has a stack based architecture. A stack based architecture is simple to implement and has few assumptions about the underlying hardware. It can be run on machines with lesser registers.
- JVM is capable of running only .class files.
- It uses JIT compiler.
DVM (Dalvik Virtual Machine) was created by Dan Bornstein and his team, keeping in mind the constraints of a mobile device. It was a purpose specific VM and was strictly created for mobile devices.
Here is a paper by David Ehringer that explains the Architecture of Dalvik Virtual Machine.
The contrasting points of DVM with JVM are:
- It uses a register based architecture.
- DVM is capable of running .dex files produced by converting .class files using a dex tool.
- It also uses JIT compiler.
AOT vs JIT
This section is very crucial in understanding the comparison of ART vs DVM in android. The main contrast in ART vs DVM is that ART uses AOT compilation whereas DVM uses JIT compilation.
More recently, ART has started using a hybrid of AOT and JIT. We’ll look into that in the later sections.
- JIT or Just In Time compiler compiles the source code into machine code during runtime. This means that each time your app is run, a part of .dex file is converted dynamically.
- As the execution goes on, more of the code is compiled and cached.
- Each file is compiled separately.
- A JIT compiler can optimize old programs as the JIT compilation process is optimized. This is not true for AOT compilation as source code is compiled beforehand.
- Adapting to run-time metrics. A JIT-compiler can not only look at the code and the target system, but also at how the code is used. It can instrument the running code, and make decisions about how to optimize according to, for example, what values the method parameters usually happen to have.
- Compiles the source code before execution.
- Improves runtime performance.
- Increased overhead during application install.
- Cannot perform optimizations such as Runtime profile guided optimizations.
- AOT compilers can perform complex and advanced code optimizations, which in most cases of JITing will be considered much too costly.
So there are the basic differences between JIT and AOT compilation processes. Now with this knowledge in the bank we’re ready to take a look at ART vs DVM in Android.
ART vs DVM in Android
DVM was designed specifically for mobile devices and was used as a virtual machine for running android apps up until Android 4.4 Kitkat.
Programs for Android are written in java and compiled to bytecode. For DVM this bytecode was eventually converted to .dex or .odex (Optimized Dalvik EXecutable ) files.
But ever since Android 4.4 Kitkat, DVM was replaced by ART (Android Runtime) which uses AOT compilation unlike DVM which used JIT.
- Uses AOT compilation. Has stricter install-time verification than DVM.
- AOT uses on device dex2oat tool to compile .dex files and generates compiled app to be run on the target device.
- Improved Garbage Collection: Garbage collection is one of the main reasons of a Janky UX, poor responsiveness and ultimately bad reviews. In the dalvik days, GC used to have 2 passes over the heap which led to janky UX.
- This situation is improved in ART with only one pass over the heap to consolidate the memory.
- Parallelized processing during the remaining GC pause.
- Collector with lower total GC time for the special case of cleaning up recently-allocated, short-lived objects
- Improved garbage collection ergonomics, making concurrent garbage collections more timely, which makes GC_FOR_ALLOC events extremely rare in typical use cases
- Compacting GC to reduce background memory usage and fragmentation.
- Leads to improved performance in app startup as there is no runtime compilation.
Other improvements in ART vs Dalvik in Android can be read here.
- Uses JIT compilation.
- It leads to slow app startup as the code is JITted each time the app starts.
- Leads to faster boot time of the device as app’s cache is built at runtime.
- Space taken by apps running on DVM have lesser memory footprint than those running on ART as ART pre-compiles applications.
- The constant pool has been modified to use only 32-bit indices to simplify the interpreter.
- Standard Java bytecode executes 8-bit stack instructions. Local variables must be copied to or from the operand stack by separate instructions. Dalvik instead uses its own 16-bit instruction set that works directly on local variables.
- Dalvik is “Deprecated” and is no longer used after android 4.4 Kitkat.
Here is an image denoting the difference in Architectures of ART vs DVM
This is the second article in the Android Internals series (here's the first). Let me know what topic you want me to cover next and I’ll be more than happy to write an article on that.
*Important*: Join the AndroidVille SLACK workspace for mobile developers where people share their learnings about everything latest in Tech, especially in Android Development, RxJava, Kotlin, Flutter, and mobile development in general.
Like what you read? Don’t forget to share this post on Facebook, Whatsapp, and LinkedIn.