A Short Exploration of Java Class Pre-Initialization

*By Qingfeng*

1. Background

Java applications are expected to start quickly because of the advent of the cloud-native era. It is becoming increasingly popular to reduce resource costs by dynamically scaling and using serverless computing. Alibaba has done a lot of work and exploration to meet the demands for quick start of applications in Serverless computing scenarios, including AppCDS, Ahead of Time Compilation (AOT), fast class indexing(JarIndex), class pre-initialization, and other technologies to optimize language runtime. Users can obtain up to three times the startup performance improvement without modifying any code. One of the cutting-edge technologies is class pre-initialization.

2. Class Pre-Initialization

2.1 Motivation

Profiling data on Java startup stage shows that the main reason for Javas’ slow startup is that it takes much time to load, link, and initialize classes, which we aim to break one by one.

Class Fidning: Fast class indexing can find corresponding Jar file of class in O(1) time

Class loading and linkage: The help of AppCDS technology can reduce time consumption and speed up the startup for load and link operations.

Class initialization: For the initialization, we observed that if the initialization of classes has no side effects, it is possible to skip the execution of the initialization of these classes. Consider the following code:

public class Foo {
private static HashMap<Integer, Integer> cache;
static {
if (cache == null) {
cache = new HashMap<>();
}
for (int i = 0; i < 1024; i++) {
cache.put(i, 0);
}
}
}

No matter when, no matter how many times, the result of initialization of the Foo class is the same: creating a hash table with a size of 1024 as a cache will not affect the external environment. In such cases, we can apply class pre-initialization, i.e. dump cache objects into CDS images, and directly map cache objects in CDS images to the Java G1 heap when JVM starts (8042668: Provide GC support for shared heap ranges in Class Data Sharing). When the program runs, skip the static code block initialization of the Foo class to speed up the startup:

public class Foo {
private static HashMap<Integer, Integer> cache; // cache is directly materialized from G1 archive region
static {
// skip execution
}
}

Another typical example is java.lang.Integer$IntegerCache class. It is an excellent candidate for class pre-initialization, which always creating a range of integer cache in [-128,127].

2.2 Class Pre-Initialization Details

The native class pre-initialization mechanism requires explicit object materialization calls (jdk.internal.misc.VM.initializeFromArchive(…)) on certain initialization point and only supports a few restricted classes, which are hard-coded in the JVM code and cannot be extended. Alibaba and Google have proposed the Eclipse Adoptium FastStartup Incubator project. They aim to explore the Java quick start technologies, including (but not limited to) class pre-initialization. As aforementioned requirements, only the initialization phase that does not take extra side effect is able to apply class pre-initialization. Alibaba and Google have explored and contributed two approaches for safe class pre-initialization.

Provides a Java annotation (jdk.internal.vm.annotation.Preserve), which allows more safe classes to be pre-initialized through manual labeling.

Add new JVM option to accept a list of safe classes. This file can be generated by static analysis tools. The static analysis tool is based on GraalVM, it scans all class initialization blocks and construct their call graph, and do further data-flow analysis on that.

At the same time, we have added a security check mechanism of class pre-initialization to the JVM to ensure the virtual machine can still work normally in the worst case. The whole workflow is shown in the figure below:

2.3 Evaluation

Class pre-initialization is based on AppCDS, performances evaluation concerns about AppCDS and itself. We found that about 90% (1800/2000) classes can be pre-initialized safely in a better scenario, average startup performance is improved by 19.2%.In a larger-scale evaluation, we found that class pre-initialization is slightly better than AppCDS, with a 5% performance improvement.

This is because some classes with high time consumption on initialization usually have side effects. They cannot be pre-initialized, but the pre-initialization of these classes will still be performed in common paths, and these hot paths will cause a performance penalty.

3. Conclusion

There have been three carriages for Java quick start for a long time: OpenJDK CRaC, JVM Runtime optimizations(AppCDS-based optimizations, AOT, JarIndex, etc), and static compilation (OpenJDK Leyden). All of them are committed to optimizing Java application startup performance from different directions. Alibaba has achieved good results in the second direction. We will continue moving forward and continuously optimize the startup performance of Java applications.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alibaba Cloud

Follow me to keep abreast with the latest technology news, industry insights, and developer trends. Alibaba Cloud website:https://www.alibabacloud.com