The state of the Java virtual machine

From its initial release, performance on the Java platform has been problematic. The first Java Virtual Machine (JVM) implementation Sun released was an interpreter, an approach that is typically far slower than native compilation. According to Dave Griswold, manager of performance for the Java platform, "People got the initial impression that the platform was slow, but the slow speed wasn't an intrinsic property of the technology." In the almost four years since that first JVM was released, Sun has been continually improving the performance of its JVM implementations. With the release of the Java 2 platform this week, the development community will be able to benefit from more of the performance improvements resulting from this effort.

Sun actually has two distinct implementations of the JVM: the "Classic JVM" and the "Hotspot JVM." The Classic JVM is built upon the foundation of the original JVM implementation -- the one that simply interpreted bytecodes. This JVM comes standard with the Java 2 platform release. The Hotspot JVM, by contrast, is a complete from-scratch rewrite. This JVM implementation will be available separately from the Java 2 platform release under terms that Sun has not yet announced. A beta version of the Hotspot JVM will be made available to a limited number of beta testers on Friday, December 11.

In addition to performance enhancements, the Java 2 platform release involves a few minor changes to the JVM specification. The APIs in Java 2 platform have also undergone changes that will impact JVM implementations. To be considered part of a compliant implementation of the Java 2 platform, all JVM implementations must adhere to these changes. According to Tim Lindholm, coauthor of the JVM specification and a key contributor to the original JVM, "Java 2 [software] is a conservative and evolutionary change as far as the JVM specification is concerned. Most performance enhancements are implementation, not specification."

JVM specification changes

The new JVM specification has one significant change: slightly relaxed rules for floating point operations. In the original specification, floating point operations were required to truncate intermediate results of calculations so they fit within the 32- or 64-bit size of the ultimate result of the operation. In the new specification, implementations are allowed to let the exponent portion of intermediate results be wider. The aim of this change in the specification is to make it easier to efficiently implement floating point on commonly available hardware, in particular Intel x86. The only place in a runtime instance of a JVM that floating point values with the wider exponent will be allowed is on the operand stack.

This change to the JVM specification also triggered the addition of a new keyword, strictfp, to the Java programming language, and the addition of a new bit to the access flags for methods in the Java class file. All JVM implementations must continue to support floating point operations as defined by the original JVM specification, which is now called "strict mode." Existing JVM implementations that adhere to the original specification already support strict mode by definition. New JVM implementations are required to perform strict floating point operations only in methods that have the ACC_STRICT access flag set in the class file. The new Java compiler will set that flag only if the programmer applied the strictfp keyword to the method or its class. (All the methods in a class declared strictfp will have their ACC_STRICT flags set.)

In Sun's Classic JVM, the default mode for methods that do not have the ACC_STRICT flag set is to use the wider exponent on the operand stack on Intel/Win32, but not on SPARC/Solaris. On Intel/Win32, the wider exponent improves the performance of floating point operations. On SPARC/Solaris, by contrast, a wider exponent would not help performance, so the Classic JVM's default mode on SPARC/Solaris is the same as strict mode.

According to David Bowen, manager of JDK engineering at Sun Microsystems, "Default mode will in most cases give you the same floating point result as strict." Only the exponent is allowed to be wider in default mode, not the significand. Thus, the result of a floating point operation in default mode will differ from the corresponding strict mode result only if the calculation overflows or underflows in strict mode in places it doesn't in default mode. Because in practice, most floating point calculations occur at a point nowhere near underflow or overflow, default mode will most often yield the same result as strict mode.

Tim Lindholm states that the new floating point rules in the JVM specification are an attempt to make a tradeoff between performance, usability, and portability. Sun's goal is to "keep [the] floating-point as simple, predictable, and reproducible as possible while allowing better performance on popular hardware."

Java API changes

Changes to the Java API in Java 2 platform that will impact implementations of the JVM include:

  • Enhanced security model
  • New extensions framework
  • Weak references

One of the most significant changes to the Java 2 platform related to the JVM is the security model. This new model builds on the 1.1 security model, which is based on a sandbox and supports code signing. But with its support for permissions and policies, the new implementation offers far more fine-grained control than its predecessor. Each type loaded into a runtime instance of a Java 2 platform JVM is assigned a set of permissions based on a security policy. These permissions define which activities the type is allowed to initiate. For example, a particular class's methods may be allowed to read from a particular file, but not write to that file. A policy, which defines permissions for code based on digital signature and location, can be described in a policy file, which is then read by the JVM.

Another major JVM-related difference between the Java 2 platform and its 1.1 predecessor involves the way classes are loaded. The class loader architecture now supports the Java Extensions Framework, which facilitates the adding in of class libraries that extend the Java platform. Once you have a Java runtime, there is a standard way to add in a library. During class loading, the runtime libraries of the Java API (these are now called the bootstrap classes) are searched first. If the requested type is found, it is loaded loader. If the type is not located in the Java API libraries, the extensions class libraries are searched. Types found here are loaded in via a class loader object. Types not found in either the bootstrap or extensions libraries are searched for in the user classes. Bootstrap, extension, and user classes are actually located in a manner determined by each JVM vendor.

Weak references are an API enhancement that will impact the design of garbage collectors in Java 2 JVM implementations. Weak references enable a program to maintain references to objects without preventing the objects from being garbage collected. In addition, programs can be notified when objects become available for garbage collection. This new functionality, which is required of all compliant implementations of the Java 2 platform, enables programs to cache information in memory and flush the cache when memory is low; to build collections of objects without preventing the objects from being garbage collected; and to implement cleanup activities that can't be performed with finalization.

Sun's Classic and Hotspot JVMs

The performance enhancements offered by Sun are found in their two Java 2 JVM implementations: Classic and Hotspot. According to David Griswold, the performance of the Classic JVM benefits from a "very good JIT compiler" and many assorted performance improvements over previous JVM releases, including:

  • Faster object allocation and garbage collection
  • Better multiprocessor scalability
  • Faster thread synchronization
  • Faster class loading

Another performance enhancement enables a Classic JVM to give memory back to the operating system as it executes. In other words, the memory image of a running JVM can now shrink as well as grow. In addition, the Classic JVM's garbage collector does not pause for garbage collection as frequently as did its JDK 1.1 cousin.

The Classic JVM architecture also supports APIs that facilitate debugging and performance tuning: a new debugger interface (the JVMDI) and a new profiler interface (the JVMPI). These APIs enable developers to select and plug into their JVM the debugger and profiler of their choice.

The Hotspot JVM uses a collection of techniques to enhance performance -- the most significant of which is called "adaptive optimization." The Hotspot JVM begins by interpreting all code, but it monitors the execution of that code. Most programs spend 80 to 90 percent of their time executing only 10 to 20 percent of the code. By monitoring the program execution, the Hotspot JVM can figure out which methods represent the program's "hot spot" -- the 10 to 20 percent of the code that is executed 80 to 90 percent of the time.

When the Hotspot JVM decides a particular method is in the hot spot, it fires off a background thread that compiles those bytecodes to native and heavily optimizes the native code, including even inlining virtual method calls. Meanwhile, the program can still execute that method by interpreting its bytecodes. Because the program isn't held up, and because the Hotspot JVM is only compiling and optimizing the "hot spot," the Hotspot JVM has more time than a traditional JIT to perform optimizations.

The adaptive optimization approach yields a program in which the code that is executed 80 to 90 percent of the time is native code as heavily optimized as statically compiled C++. All this with a memory footprint not much bigger than a fully interpreted program. In plain English: it's fast. The Hotspot JVM keeps the old bytecodes around in case a method moves out of the hot spot. (The hot spot may move somewhat as the program executes.) If a method moves out of the hot spot, the JVM can discard the compiled code and revert back to interpreting that method's bytecodes.

In addition to the adaptive optimization technique, the Hotspot JVM includes several other improvements that address performance bottlenecks in current VMs. For example, Sun claims interface method invocations in Hotspot will not have a performance disadvantage compared to other method invocations. Improved thread synchronization will make invoking a synchronized method much faster, and only a little more expensive than invoking a nonsynchronized method. Finally, Hotspot uses a generational garbage-collection algorithm, which reduces the cost of collecting large numbers of short-lived objects. According to Dave Griswold, the garbage collection of short-lived objects (which typically represent 90 percent or more of all objects) is almost two times faster in Hotspot than malloc() and free() in C.

Stability, performance, and compatibility

So what is the current state of the Java Virtual Machine? One area in which Java technology's compatibility and stability problems still persist is in Web browsers. According to Frank Greco, president and CEO of Crossroads Technologies, "for mission critical applications, you don't use applets." The trouble with applets is that the different browsers, even different browser versions from the same vendor, are not bug-for-bug compatible, making it difficult to write an applet that works in all versions of all browsers. In addition, many browsers have a tendency to crash too often to be suited for hosting a mission-critical client.

Sun offers one potential solution to the browser compatibility problem: the Java Plug-in. The Java Plug-in enables users to replace their browser's embedded JVM with one of Sun's JVMs. This technology can help enterprises overcome browser inconsistencies and make deploying applets on an intranet a more viable option.

Outside the browser arena, the compatibility, stability, and performance of Sun's JVM implementation appears to be reasonably good. According to John Neffenger, founder and CTO of Volano LLC, "all the leading JVMs are stable." Volano created the VolanoMark, a "torture test for sockets and threads," to characterize the performance of its Java platform-based chat server on different platforms using various JVM implementations. Neffenger said that "Volano will have at least five JVMs that deliver the speed, stability, and scalability that the Java platform deserves."
