Free, Fast, Open, Production-Proven, and All Java: OpenJ9
Take a deep dive into OpenJ9, a high-performance, production-ready, enterprise-grade JVM implementation that serves as an alternative to HotSpot.
Join the DZone community and get the full member experience.Join For Free
Eclipse OpenJ9 is a high-performance, scalable, Java virtual machine (JVM) implementation. It is not new. It has been part of the IBM Java Development Kit for many years and it is safe to say that it is an enterprise-grade, production-level component of many large Java-based systems. At the end of last year, it was contributed to the Eclipse Foundation by IBM. OpenJ9 is an alternative to the Hotspot JVM currently mostly used within OpenJDK.
Although the Eclipse OpenJ9 project hasn't been around for very long, the VM itself has been around for years. It was launched during the fourth JavaOne and parts of the codebase can be traced back to Smalltalk.
It has been powering IBM middleware products for the last decade or more. IBM contributed the VM to the Eclipse Foundation end of 2017 and more than 70 IBM developers are actively involved in the project.
The long-term goal of the Eclipse OpenJ9 project is to foster an open ecosystem of JVM developers that can collaborate and innovate with designers and developers of hardware platforms, operating systems, tools, and frameworks. The Java community has benefited over its history from having multiple implementations of the JVM specification competing to provide the best runtime for your application. Whether adding compressed references, new cloud features, AOT (ahead-of-time) compilation, or straight up faster performance and lower memory use, the ecosystem has improved through that competition. Eclipse OpenJ9 aims to continue to spur innovation in the runtimes space.
As an essential part of this, the teams work closely with the AdoptOpenJDK efforts, which are led by the London Java Community. If you look closely, you realize that a large part of OpenJ9 has been living at the Eclipse Foundation for a couple of years now. Eclipse OpenJ9 embeds Eclipse OMR, which provides cross-platform components for building reliable, high-performance language runtimes.
Eclipse OpenJ9 takes OMR and adds extra code that turns it into a runtime environment for Java applications.
What Exactly Is Exactly Is OpenJ9 and How Does it Relate to OpenJDK?
OpenJ9 replaces HotSpot JVM in the OpenJDK build and becomes a new JVM runtime implementation that can be used with a wide range of system architectures and operating systems. Currently, there are pre-built OpenJDK binaries with OpenJ9 as the JVM available for Java versions 8, 9, and 10 via the AdopOpenJDK project website. A JVM is not the complete Java Development Kit (JDK). It is the execution engine. While the JDK provides tools, class libraries, and more general things that you need to build your application, the JVM is responsible to run the actual bytecode. It is a replacement for the commonly used and known Hotspot JVM which was implemented by Oracle.
In order to create an OpenJDK build with OpenJ9 as the JVM, the OpenJDK project is mirrored into a separate repository that removes Hotspot and provides a place for the needed integration code. The integration code consists mostly of changes to Makefiles and configuration, some patches to the class library code (JCL), and some minor patches for additional OpenJ9 features.
The integration layer mitigates the few places where the interfaces from Hotspot and OpenJ9 are slightly different. All in all, it is roughly 4,000 lines of code, which is really small compared to the size of OpenJ9 or the OpenJDK. The primary goal is to keep this to a necessary minimum and also contribute as much as possible upstream to the OpenJDK.
With OpenJDK, with the integration code and OpenJ9 coming together via a build process, the end result is a binary that is available for a range of different platforms.
You can find more information about the build process and how to build your own OpenJDK with OpenJ9 on the project website.
Why OpenJ9 Is the Perfect Cloud Runtime
The requirements of cloud runtimes today are different to the characteristics employed by individual, physical machines in the datacenters from just a couple of years ago. A small memory footprint allows a higher application density for providers and reduces the cost per application for users as they can run more instances with less resources.
Another important feature is a fast startup, which lets application instances scale faster and more smoothly.
The OpenJ9 project uses the Daytrader application to monitor performance improvements in comparison with Hotspot. With a 66% smaller memory footprint after startup and a 42% faster startup time, it reaches a comparable throughput in a constraint environment like a Docker container.
Uinque Features and Advantages
The lower memory footprint and faster startup times demonstrate the practical impact of some of the advantages and implementation differences over the classical Hotspot JVM.
Application Class Sharing and AOT Compilation
The first time an application runs, the JVM has to load all the classes that are required to start the application. This process takes time. If the needed classes are stored in cache, the second application run will be much faster. Another implementation difference is that the JVM doesn't store the Java bytecode classes but an optimized ROMClass version of it. These read-only, optimized versions are carrying symbolic data only. When the JVM is executing a class, it has to be able to do a bunch of lookups, e.g. finding the method it is actually invoking, and it also needs to be able to work on data and save this data. This is where the J9RAMClass comes in. It is a cache for the data at runtime and carries the live data for a particular class.
Further on, the ROMClasses can be shared between multiple JVMs on the same machine. OpenJ9 always shares both the bootstrap and application classes that are loaded by the default system class loader. A detailed view on how this works is available in this article. And there is something else that can be optimized with this shared class cache ahead-of-time compilation (AOT). Unlike just-in-time (JIT) compilation, AOT is dynamically compiling methods into ATO code at runtime and placing these ROMClasses into the shared cache. The VM automatically chooses which methods should be AOT-compiled based on heuristics that identify the start-up phase of large applications. It is enabled via the -Xshareclasses option, which is highly configurable.
As for AOT itself, it works straight out of the box when you enable shared classes and doesn't require any special tuning.
Tuning for Cloud Environments
The -Xtune:virtualized option is designed to configure OpenJ9 for typical cloud deployments where VM guests are provisioned with a small number of virtual CPUs to maximize the number of applications that can be run. The -Xquickstart option enables an ultra-fast startup of OpenJ9 and works best with short-lived tasks. But be aware that you may trade in the peak throughput capabilities. You can also specify -XX:+IdleTuningGcOnIdle on the command line. When set, OpenJ9 determines whether an application is idle based on CPU utilization and other internal heuristics. When an idle state is recognized, a GC cycle runs if there is significant garbage in the heap and releases unused memory back to the operating system. A more detailed overview is provided in this article.
Garbage Collection in OpenJ9
Eclipse OpenJ9 has a number of GC policies designed around different types of applications and workloads. The Generational Concurrent (-Xgcpolicy:gencon) GC policy is the default policy employed by the JVM. But there are four other alternatives: -Xgcpolicy:balanced, -Xgcpolicy:metronome, -Xgcpolicy:optavgpause, and -Xgcpolicy:optthruput. The Metronome GC (-Xgcpolicy:metronome) policy is especially interesting if your application depends on precise response times and you are running on x86 Linux. The main difference between Metronome and other policies is that garbage collection occurs in small interruptible steps rather than stopping an application completely while garbage is marked and collected.
By default, Metronome pauses for three milliseconds at a time. A full garbage collection cycle requires many pauses, which are spread out to give the application enough time to run. You can limit the amount of CPU that the GC process uses and you can control the pause time. A more complete overview about the individual policies can be found in this article.
The AdoptOpenJDK project releases pre-built binaries for Linux x64, Linux s390x, Linux ppc64, and AIX ppc64. The easiest way to get started is to download the one for your operating system and start working with it — although you have the ability to build binaries for other platforms like Linux ARMv7 yourself. Docker images are available via DockerHub.
The JVM documentation is extensive and well-structured to get you started with optimizing for your application.
Opinions expressed by DZone contributors are their own.