Android inside out: a comparison of Dalvik and ART

Hello, Habr! About half a year ago I published a detailed JVM "guide" . The post, in general, went, and in the comments they asked if "something is planned for android". Finally, I got my hands on it.







In this post, we will talk about the Android runtime. In particular, I will try to briefly but succinctly outline how ART and Dalvik differ, and how Android development tools have improved over time. The topic is clearly not new, but I hope it will come in handy for those who are just beginning to delve into it. Who cares - welcome to cat.



Virtual machine



First, let's see how the JVM differs from the DVM.



Java Virtual Machine is a virtual machine capable of executing Java bytecode regardless of the underlying platform. It is based on the “Write once, run anywhere” principle. Java bytecode can be run on any machine capable of supporting the JVM.



The Java compiler converts .java files to class files (bytecode). The bytecode is passed to the JVM, which compiles it to machine code for execution directly on the CPU.



JVM features:



  • It has a stack architecture: a stack is used as a data structure where methods are placed and stored. It works in LIFO or “Last in - First Out” or “Last in, first out” scheme.
  • Can only run class files.
  • Uses a JIT compiler.


The Dalvik Virtual Machine (DVM) is a Java virtual machine developed and written by Dan Bornstein and others as part of the Android mobile platform.



We can say that Dalvik is the environment for executing Android operating system components and custom applications. Each process runs in its own isolated address space. When the user launches the application (or the operating system launches one of its components), the Dalvik virtual machine core (Zygote Dalvik VM) creates a separate, protected process in shared memory, in which the VM is directly deployed as an environment for launching the application. In other words, from the inside, Android looks like a set of Dalvik virtual machines, each of which runs an application.



Features of DVM:



  • Uses a register-based architecture: the data structure where methods are placed is based on processor registers. Due to the absence of POP and PUSH operations, instructions in a registered virtual machine execute faster than similar instructions in a stacked virtual machine.
  • Executes native format bytecode: Android dexer (we'll talk about it below) converts class files to .dex format, optimized for execution on Dalvik VM. Unlike a class file, a dex file contains several classes at once.








You can read more about DVM architecture here .



Android Dexer



Android developers know that the process of converting Java bytecode to .dex bytecode for Android Runtime is a key step in creating an APK. The dex compiler mostly works under the hood in day-to-day application development, but it directly affects application build time, .dex file size, and runtime performance.



As already mentioned, the dex file itself contains several classes at once. Duplicate lines and other constants used across multiple class files are included only to save space. Java bytecode is also converted into an alternate instruction set used by DVM. The uncompressed dex file is usually a few percent smaller than the compressed Java archive (JAR) obtained from the same .class files.



Initially, class files were converted to dex files using the built-in DX compiler. But from Android Studio 3.1 onwards, D8 became the default compiler . Compared to the DX compiler, D8 compiles faster and outputs smaller dex files, while providing better application performance at runtime. The dex bytecode obtained in this way is minified using the open-source ProGuard utility . As a result, we get the same dex file, but smaller. This dex file is then used to build the apk and finally to deploy to an Android device.







But behind D8 in 2018 came R8, which, in fact, is the same D8, only with additions.



When working with Android Studio 3.4 and Android Gradle 3.4.0 plugin or higher, Proguard is no longer used to optimize code at compile time. Instead, the plugin works by default with R8, which does Code shrinking, Optimization, and Obfuscation itself. Although R8 only offers a subset of the functionality provided by Proguard, it allows you to do the conversion of Java bytecode to dex bytecode once, which further reduces build time.







R8 and code reduction





Typically, apps use third party libraries like Jetpack, Gson, Google Play Services. When we use one of these libraries, often the application uses only a small portion of each individual library. Without Code shrinking, all library code is stored in your application.



It happens that developers use verbose code to improve the readability and maintainability of an application. For example, meaningful variable names and a design pattern can be used to help others understand the code more easily. But templates tend to lead to more code than necessary.



This is where the R8 comes to the rescue. It can significantly reduce the size of the application, optimizing the size of even the code that is actually used by the application.



As an example, below are the numbers from the Shrinking Your App with R8 report , which was presented at the Android Dev Summit '19:







And this is how the comparison of the effectiveness of R8 at the beta release stage looked like (taken from the source Android Developers Blog ):













More details can be found in the office documentation and report .



ART vs DVM in Android



DVM was designed specifically for mobile devices and was used as a virtual

machine to run android applications up to Android 4.4 Kitkat.



Starting with this version, ART was introduced as a runtime, and in Android 5.0 (Lollipop) ART completely replaced Dalvik.



The main clear difference between ART and DVM is that ART uses AOT compilation, and DVM uses JIT compilation. Not so long ago, ART started using a hybrid of AOT and JIT. Let's take a closer look at this.



DVM



  • Uses JIT compilation: whenever the application starts,
  • the part of the code that is needed to run the application is compiled. The rest of the code is compiled dynamically. This slows down the launch and operation of applications, but reduces installation time.
  • , .
  • , DVM, , , ART.
  • , CPU.
  • Dalvik “” 4.4.






ART



  • AOT , . , .
  • , .
  • AOT , DVM.
  • , - .
  • Improved Garbage Collection or Garbage Collection. When using Dalvik, the garbage collectors had to do 2 heap passes, which led to poor UX. In the case of ART, there is no such situation: it cleans the heap once to consolidate memory.






And a small diagram of Dalvik vs ART:





JIT + AOT in ART



The Android Runtime (ART) since Android 7 includes a JIT compiler with code profiling. The JIT compiler complements the AOT compiler and improves runtime performance, saves disk space, and speeds up application and system updates.



This happens in the following way:





Instead of running the AOT compilation of each application during the installation phase, it runs the application under the control of a virtual machine using a JIT compiler (almost the same as in Android <5.0), but keeps track of which sections of application code are executed most often. This information is then used to AOT compile these code sections. The latter operation is performed only when the smartphone is inactive while it is charging.



In simple terms, now two completely different approaches work together, which gives its advantages:



  • more efficient compilation - when running an application in real time, the compiler has the opportunity to learn much more about its work than by performing static analysis, and, as a result, more appropriate optimization methods are applied for each situation;
  • preservation of RAM and permanent memory - byte code is more compact than machine code, and if you perform AOT compilation of only certain sections of the application and do not compile applications that the user does not use, you can significantly save NAND memory space;
  • dramatic increase in installation and first boot speed after system update - no AOT compilation, no delay.


Read more about the implementation of the JIT compiler in ART here .



Conclusion



In this article, I tried to take a look at the main differences between Dalvik and ART, and generally take a look at how Android has improved its development tools over time.



ART is still under development with new features being added to improve the experience for both users and developers.



If it was helpful, let me know in the comments.



All Articles