The basics of Java platform performance

Where to focus your efforts

Java's architecture comprises four distinct and interrelated technologies: language, classfile format, Java API libraries, and Java Virtual Machine (JVM). When executing a Java application, the source code is written in the Java language, which is compiled into the classfile format, which in turn is executed in the JVM. Additionally, Java applications call methods from the Java API libraries that provide access to system resources (e.g., graphics, networking, disk I/O, and the like). Together, the JVM and Java API libraries form a compile and runtime execution environment, which is also known as the Java platform.

Java achieves architectural independence by compiling its source code into its own intermediate representation, not the typical machine-specific op-codes of a particular hardware platform. The intermediate representation is called byte code. The byte code produced is designed to run in a stack-based architecture. Unlike the assembly-language representation of most modern machines that are register based, a stack-based machine has no registers. The JVM is an abstract computer architecture based on a dynamic stack that provides operations to push, pop, and manipulate data. The JVM's main function is to load classfiles and execute the resulting byte codes.

Platform execution workload

Programmers can tune four main execution workloads in the JVM in order to improve performance. Typically, the execution workload of the JVM is segmented into byte code execution, garbage collection, thread management, and dynamic operations (e.g., dynamic class loading, type checking, and so on).

Byte code execution

Typically, the JVM spends approximately half of its time interpreting byte code. Using a just-in-time (JIT) compiler reduces byte-code interpretation and causes the execution workload to shift to native compilation and caching of native methods.

Garbage collection

Garbage collection varies according to the garbage collector's algorithm and how efficiently a program manipulates objects; object-oriented languages such as Java make heavy use of memory resources.

Thread management

Thread synchronization varies according to the thread monitor's efficiency and the number of threads a program spawns. Thread synchronization is a runtime task that typically provides room for improvement.

Dynamic operations

Dynamic operations include class loading, bounds checking, security measures, dynamic class loading, exception handling, reflection, and native method translation. The JVM also checks for null pointers, division-by-zero errors, illegal string-to-number conversions, invalid type casting, and a host of other exceptions.

Improving byte code execution: HotSpot and JITs

The Java HotSpot performance engine is Sun's next-generation compilation technology that compiles only performance-critical code. The latest version of HotSpot provides both client- and server-side solutions.

A JIT compiler simply compiles byte code as it executes. JIT refers to the fact that it compiles byte code only when it's ready to be executed -- just in time, in other words. JIT compilers are very powerful because only code that actually executes is compiled; methods that are executed frequently can be retrieved from the native method cache at execution time and executed on the fly. There is one big issue with JIT compilers: once a method has been compiled, it loses the power of portability, because it has been compiled to the native code of the hardware and consequently isn't portable any longer.

HotSpot has a dynamic compiler, but it differs from a JIT in that it uses heuristics to determine which section of the code should be executed and is more aggressive when optimizing the selected code than a typical JIT compiler.

Reggie Hutcherson is a Sun technology evangelist. He evangelizes Sun's Java 2 Platform technologies worldwide, concentrating on J2SE and the HotSpot performance engine.

Learn more about this topic