Eclipse OpenJ9 (previously known as IBM J9) is a high performance, scalable, Java virtual machine (JVM) implementation that is fully compliant with the Java Virtual Machine Specification.[3]
OpenJ9 can be built from source, or can be used with pre-built binaries available at the IBM Semeru Runtimes project for a number of platforms including Linux, Windows[4] and macOS. OpenJ9 is also a core component of the IBM developer kit, which is embedded in many IBM middleware products, including WebSphere Application Server and Websphere Liberty. OpenJ9 is also a component of Open Liberty.[5]
Extensive configuration options ensure that the JVM can be tuned to satisfy the requirements of a wide range of Java applications, from complex enterprise applications that run on mainframe hardware to short-lived applications that run on container-based cloud services.
History
OpenJ9 can trace its roots back to the ENVY/Smalltalk product developed by Object Technology International (OTI). IBM purchased OTI in 1996 for their Smalltalk expertise and products. However, when the Java language emerged as a leading language for the enterprise market, the existing Smalltalk VM was adapted to process Java bytecodes instead. The name J9 evolved from the naming convention for the Smalltalk source code, K8. K→J (a backward step) because the developers believed that Smalltalk was better than Java, but 8→9 (a forward step) because the new VM would be better than before.[6]
The J9 JVM became the runtime engine for many of IBM's enterprise middleware products, where it has built its reputation for high performance, scalability, and reliability.
In 2017, J9 became an Eclipse Foundation project under the name Eclipse OpenJ9. IBM continue to be actively involved in the project and continue to put this Java VM at the core of many software offerings. At the Eclipse Foundation, OpenJ9 is classified as an incubator project, with the first release, v0.8.0, delivered in 2018.
Features
The Eclipse OpenJ9 JVM is fully compliant with the Java JVM specification. The same version of the JVM can be used in OpenJDK 8 and later releases, which means that many features and improvements can be exploited by applications that run on different versions of Java. Compared to Oracle's HotSpot VM, OpenJ9 touts higher start-up performance and lower memory consumption at a similar overall throughput.[7]
Eclipse OpenJ9 embeds Eclipse OMR, which provides core runtime components that can be used to build runtime environments for different programming languages. At the OpenJ9 project, an extra layer of code adds the language semantics to provide a runtime environment for Java applications.[8]
The components that make up Eclipse OpenJ9 are described in the following sections:
JIT compiler
The Just-In-Time (JIT) improves the performance of Java applications by compiling platform-neutral Java bytecode into native machine code at run time. Not every method that gets called by an application is compiled. Instead, OpenJ9 records the number of times a method is called and triggers JIT compilation at a predefined threshold. The JIT compiler compiles methods at different optimization levels: cold, warm, hot, very hot (with profiling), or scorching. The hotter the optimization level, the better the expected performance, but the higher the cost in terms of CPU and memory.
The higher optimization levels use special techniques such as escape analysis and partial redundancy elimination, or loop through certain optimization sequences more times. Although these techniques use more CPU and memory, the improved performance that is delivered by the optimizations can make the trade-off worthwhile.
AOT compiler
Ahead of Time (AOT) compilation is a mechanism for improving start up performance. Methods are dynamically compiled into AOT code at runtime, which enables the JVM to start an application faster. AOT is enabled automatically when class data sharing is used (-Xshareclasses) and doesn't require any special tuning. OpenJ9 automatically chooses which methods to compile based on heuristics that identify the start-up phase of large applications. For small or short running applications, the -Xtune:virtualized option should be added to get the most out of AOT-compiled code.
Class data sharing
Sharing class data between JVMs has two main benefits:
Start up performance is improved by placing classes that an application needs when initializing into a shared classes cache.
Memory footprint is reduced by sharing common classes between applications that run in separate Java VMs.
Unlike other class data sharing (CDS) implementations, enabling the feature in OpenJ9 requires only one step: setting -Xshareclasses on the command line when you start your application. When specified, OpenJ9 creates a memory mapped file to store and share the classes in memory. By default, OpenJ9 always shares both the bootstrap and application classes that are loaded by the default system class loader. Another benefit of the OpenJ9 CDS implementation is that the cache is updated dynamically. So when an application loads new classes, the JVM automatically stores them in the cache without any user intervention.[9]
OpenJ9 also provides a public Helper API for integrating class sharing support into custom class loaders, plus several utilities for managing active caches.
Garbage collector
To prevent applications running out of memory, objects in the Java heap that are no longer required must be reclaimed. This process is known as garbage collection (GC). OpenJ9 provides a number of garbage collection policies that are designed around different types of applications and workloads. Choosing the right policy depends on usage and performance goals. By default, OpenJ9 uses the Generational Concurrent (-Xgcpolicy:gencon) policy, which is best suited to transactional applications that have many short lived objects. Alternative policies are available, including those that cater for applications with large Java heaps (-Xgcpolicy:balanced), applications that are sensitive to response-time (-Xgcpolicy:metronome), or applications that require high application throughput (-Xgcpolicy:optthruput).
An "idle tuning" option (-XX:+IdleTuningGcOnIdle) triggers garbage collection in OpenJ9 when the application is idle. Doing this reduces memory footprint, meaningful for some virtual hosting billing plans.[7]
JIT server
In January 2020, OpenJ9 delivered an experimental feature to JIT compile code outside JVM and remotely on a server.
Diagnostic component
OpenJ9 contains extensive trace and debugging utilities to help identify, isolate and solve runtime problems. Different types of diagnostic data are automatically produced by default when certain events occur, but can also be triggered from the command line. Types of data include:
Java dumps
These are produced when the JVM ends unexpectedly because of an operating system signal, OutOfMemoryError exception, or a user initiated keystroke combination. Java dumps summarize the state of the JVM when the event occurs, with most of the information relating to components of the JVM.
Heap dumps
Heap dumps show all the live objects on the Java heap when the JVM ends because of an OutOfMemoryError exception or when requested by a user. The information includes object address, type or class name, size, and references to other objects. Analyzing heap dumps might tell you which objects are using large amounts of memory on the Java heap and why these are not being garbage collected.
System dumps
Often known as core dumps, these are platform-specific and contain a raw binary dump of the process memory. This dump has a complete copy of the Java heap, including the contents of all Java objects in the application. OpenJ9 tools are available to process the system dump into a readable format for analysis.
Garbage collection data
To analyze garbage collection problems you can enable verbose logging, which provides data on all garbage collection operations including initialization, stop-the-world processing, finalization, reference processing, and allocation failures. For even more detailed analysis, you can turn on garbage collection tracing.
Trace data
The OpenJ9 trace facility can be used to trace applications, Java methods, or internal JVM operations with minimal impact on performance.
JIT data
If a general protection fault or abort event takes place, the JIT produces a small binary dump that can be analyzed by OpenJ9 developers to help determine the root cause.
Shared classes data
The shared classes data component provides some verbose options that can be used at runtime to show cache activity. The printStats and printAllStats utilities allow you to analyze the contents of a shared class cache.
The diagnostic component also includes the DTFJ application programming interface, which can be used to build diagnostic tools. DTFJ works with data from a system dump or a Java dump.
Adoption
IBM:Semeru Runtime (OpenJ9 with OpenJDK) community builds are now built, tested and distributed as IBM Semeru.[10] The Semeru runtimes use the OpenJ9 JVM with the OpenJDK class libraries.