Java HotSpot Virtual Machine

 

 

Architecture

There are two main parts to the HotSpot system:

  1. runtime
  2. compiler

The runtime portion includes a bytecode interpreter, memory management and garbage collection functionality, and machinery for handling thread synchronization and other low-level tasks. The compiler's job is simply to translate bytecodes into native machine instructions, thus improving execution speed.

Note that it is possible to use the HotSpot VM as a fully compliant JVM without the compiler. The only difference will be a decrease in performance.

 

Two Versions of HotSpot

When the first version of the HotSpot VM was shipped in April 1999, it was dubbed the Java HotSpot Performance Engine. The Java HotSpot Performance Engine made major improvements in the performance of many server-side applications. However, it wasn't ideal for many client-side programs. The requirements for client and server can be quite different. For example, client programs often favor lower RAM footprint and faster start-up time over maximum computational performance. Due to these different requirements, the HotSpot technology was split into two lines-one for the client and one for the server.

 

HotSpot Compiler != javac

The terminology used here can be confusing. The javac tool included with the J2SDK is a source-code to bytecode compiler. The "compiler" included with the HotSpot VM is a bytecode to native machine-code compiler. Though they're both generically referred to as compilers, they perform very different tasks. This terminology sometimes leads to the mistaken impression that you have to compile your source code with a different compiler to use the HotSpot VM. This is not the case. Any class files that execute on older JVMs should run under the HotSpot VM without modification.

As of version 1.3 of the J2SE SDK, all of Sun's implementations include a version of the HotSpot Client VM. The HotSpot Server VM is an optional add-on. The Client VM and the Server VM are very similar, and actually share a lot of code. The only part of the system that is different is the compiler. The Server VM contains a highly advanced adaptive compiler that supports many of the same types of optimizations performed by optimizing C++ compilers (as well as a few optimizations C++ compilers only wish they could do). The Client VM is much simpler. It doesn't try to perform many of the more complex optimizations performed by the compiler in the Server VM, but in exchange the Client VM requires less time to analyze and compile a particular piece of code. This means that the Client VM can start up faster, and requires less warm-up time to reach peak performance.

 

Runtime Features

Both the HotSpot Client VM and the HotSpot Server VM share the same runtime code. The runtime is primarily responsible for the following types of operations:

  • Interpretation of bytecodes
  • Memory allocation and garbage collection
  • Thread synchronization

Simple JIT compilers compile all methods before they are executed. This turns out to be wasteful, as many methods are only executed once (or a very few times). In such cases, the time to compile the method can dwarf the time required to execute it. All this compilation also increases memory usage because the compiled code must be stored. As a result, the HotSpot runtime executes many methods in a purely interpreted mode. To ensure maximum performance for these methods, the HotSpot runtime provides a highly optimized bytecode interpreter.

In addition to the bytecode interpreter, the runtime is responsible for memory management and thread synchronization. The HotSpot runtime provides several important optimizations in these areas.

 

Memory Allocation and Garbage Collection

The HotSpot runtime provides an exact, generational, incremental, garbage collector that makes several design guarantees:

  • All logically inaccessible object memory can be reclaimed reliably.

  • All objects can be relocated, allowing object memory compaction to eliminate object memory fragmentation and increases memory locality.

 

Generational Copying Collection

The HotSpot runtime employs a generational copying collector that provides two major benefits:

  1. Major increases in both allocation speed and overall garbage collection efficiency (often by more than a factor of 5) for most programs, compared to the Java 2 SDK

  2. A corresponding decrease in the frequency of user-perceivable garbage collection pauses

A generational collector takes advantage of the fact that, in most programs, the vast majority of objects (often greater than 95 percent) are very short-lived. By allocating objects from a dedicated object "nursery," a generational collector can accomplish several things.

  • Because new objects are allocated contiguously in stacklike fashion in the object nursery, allocation becomes extremely fast. This is because it involves merely updating a single pointer and performing a single check for nursery overflow.

  • By the time the nursery overflows, most of the objects in the nursery are already "dead," allowing the garbage collector to simply move the few surviving objects elsewhere. This way, it avoids doing any reclamation work for dead objects in the nursery.

 

Mark-Compact "Old Object" Collector

Although the generational copying collector collects most dead objects efficiently, longer-lived objects still accumulate in the "old object" memory area (old objects are objects that have existed for a while in machine terms). Occasionally, based on low-memory conditions or programmatic requests, an old-object garbage collection must be performed. The HotSpot runtime can use a standard mark-compact collection algorithm, which traverses the entire graph of live objects from its "roots," and then sweeps through memory, compacting away the gaps left by dead objects. By compacting gaps in the heap rather than collecting them into a free list, memory fragmentation is eliminated, and old-object allocation is streamlined by eliminating freelist searching.

 

Incremental "Pauseless" Garbage Collector

The mark-compact collector does not eliminate all user-perceivable pauses. User- perceived GC pauses occur when old objects need to be garbage collected, and these pauses are proportional to the amount of live object data that exists. This means that the pauses can become arbitrarily large as more data is manipulated, which is a very undesirable property for server applications, animations, and other soft real-time applications.

The HotSpot runtime provides an alternative old-space garbage collector to solve this problem. This collector is fully incremental, eliminating most user-detectable garbage collection pauses. This incremental collector scales smoothly, providing relatively constant pause times even when extremely large object datasets are being manipulated. This provides excellent behavior for:

  • Server applications, especially high-availability applications
  • Applications that manipulate very large live object data sets
  • Applications where all user-noticeable pauses are undesirable, such as games, animations, and other highly interactive applications

The pauseless collector works by using an incremental old-space collection scheme referred to academically as the "train" algorithm. This algorithm breaks up old-space collection pauses into many tiny pauses (typically less than 10 milliseconds) that can be spread out over time so that the program virtually never appears to pause to a user. Since the train algorithm is not a hard real-time algorithm, it cannot guarantee an upper limit on pause times; however, in practice much larger pauses are extremely rare, and are not caused directly by large datasets.

The pauseless collector also has the highly desirable side benefit of producing improved memory locality. This happens because the algorithm works by attempting to relocate groups of tightly coupled objects into regions of adjacent memory, which provides excellent paging and cache locality properties for those objects. This can also benefit highly multithreaded applications that operate on distinct sets of object data.

 

B.2.2 Thread Synchronization

Another big attraction of the Java programming language is the provision of language-level thread synchronization, which makes it easy to write multithreaded programs with fine-grained locking. Unfortunately, older JVMs' synchronization implementations are highly inefficient relative to other micro-operations in the Java programming language, making use of fine-grain synchronization a major performance bottleneck.

HotSpot incorporates a unique synchronization implementation that boosts performance substantially. The synchronization mechanism provides its performance benefits by providing ultra-fast, constant-time performance for all uncontended synchronizations, which dynamically comprise the great majority of synchronizations.

The Java HotSpot synchronization implementation is fully suitable for multi-processing, and exhibits excellent multiprocessor performance characteristics.

 

HotSpot Server Compiler

While the HotSpot Client VM uses fairly traditional compilation technology, the HotSpot Server VM uses many advanced techniques to achieve maximum computational performance. A few of these optimizations are described in the next three sections.

 

Aggressive Inlining

Method inlining is an important compiler optimization. However, static compilers are restricted in the amount of inlining they can do, for a couple of reasons. First, a static compiler can inline a method only if the compiler can determine that method is not overridden in a subclass. A static compiler can inline static, final, and private methods because it knows those methods can't be overridden. However, public and protected methods can be overridden in a subclass, and static compilers therefore cannot inline those methods.

Second, even if it were possible to determine through static analysis which methods are overridden and which are not, a static compiler still could not inline public and protected methods. The Java language allows classes to be loaded during runtime, and such dynamically loaded classes can change the structure of a program significantly. In particular, such dynamic loading can render invalid any inlining that was done based on pre-runtime, static analyses.

The HotSpot dynamic compiler uses runtime analysis to perform inlining aggressively, yet safely. Once the HotSpot profiler has collected runtime information about program hot spots, it not only compiles the hot spot into native code, but also performs extensive method inlining on that code. The HotSpot compiler can afford to be aggressive in the way it inlines because it can always back out an inlining optimization if it determines that the method inheritance structure has changed during runtime due to dynamic class loading.

The HotSpot VM can revert to using the interpreter whenever compiler deoptimizations are called for because of dynamic class loading. When a class is loaded dynamically, the HotSpot VM checks to ensure that the interclass dependencies of inlined methods have not been altered. If a dynamically loaded class affects any dependencies, the HotSpot VM can back out affected inlined code, revert to interpreting for a while, and reoptimize later based on the new class dependencies.

On the other hand, when running statically compiled code, a JVM does not have access to the original bytecodes, and cannot fall back on an interpreter when optimizations in the statically compiled code become unsafe. Therefore, static compilers cannot be as aggressive in their optimizations as dynamic compilers, which results in slower performance.

The extensive inlining enabled by the dynamic compiler gives it a huge advantage over static compilers. Inlining reduces the number of method invocations and their associated performance overhead. This is a significant bonus with the Java programming language, in which methods are virtual by default and method invocations are frequent.

Method inlining is also synergistic with other optimizations. Inlining produces large blocks of code that make additional optimizations easier for the compiler to perform. The HotSpot Server compiler's ability to perform aggressive inlining is a key factor in making it faster than current JIT and static compilers.

 

Other Optimizations

The optimizer performs all of the classic optimizations such as dead code elimination, loop invariant hoisting, common subexpression elimination, and constant propagation. It also features optimizations more specific to Java technology, such as null-check elimination. The register allocator is a global graph coloring allocator and makes full use of large register sets.

 

Array Bounds Checks

None of the current generation of HotSpot compilers eliminate unnecessary array bounds checks. While it is theoretically possible to automatically remove many array bounds-related computations from certain types of loop structures, the HotSpot compiler doesn't yet do this. The HotSpot engineering team has run tests that show that only a small improvement in performance on the SpecJVM benchmark is to be expected when this feature is implemented. Specific applications might see much larger increases, however, depending on the amount of array access that they perform.

 

-X Flags

Both the HotSpot Client and Server VMs enable some control over the performance of the virtual machine. In some special circumstances, these options can be important. Keep in mind, however, that they are all nonstandard and subject to change without notice. Table B-1 shows all of the special HotSpot options.

Option Description
-Xmixed Mixed mode execution (default)
-Xint Interpreted mode execution only
-Xbootclasspath:path Search path for bootstrap classes and resources
-Xnoclassgc Disable class garbage collection
-Xincgc Enable incremental garbage collection
-Xbatch Disable background compilation
-Xms<size> Initial Java heap size
-Xmx<size> Maximum Java heap size
-Xprof Output CPU profiling data

 

-Xnoclassgc

This flag turns off class unloading. Under JDK 1.1.x, this was important in some circumstances. With Java 2, however, the semantics of class loading are such that you really don't ever need to use this flag.

 

-Xincgc

This option enables the incremental garbage collector and reduces the average length of garbage collection pauses. Even without the incremental collector, pauses are usually not user-detectable. However, some applications have stringent requirements about how often certain operations need to happen. The incremental collector isn't designed for hard real-time applications, but can be useful in many soft real-time situations where concrete guarantees about CPU time are not required.

 

-Xbatch

This flag disables background compilation. By default, the HotSpot VM can compile methods in the background while they are executing. This smooths operation by eliminating the pauses that can occur when waiting for a method to be compiled. However, compiling methods in the background does have a slight performance impact. Using the -Xbatch flag on server processes that don't directly interact with the user might result in higher peak performance on single-processor servers. In general, using this flag hurts performance on multiprocessor machines because compilation could otherwise be off-loaded to a different processor.

 

-Xms

This flag sets the initial size of the object heap. The current default is 2MB. Increasing this size can help improve startup time for applications that need large heaps by eliminating the extra garbage collection that occurs before the heap is automatically expanded.

 

-Xmx

This flag sets the maximum size of the Java heap. It currently defaults to 64MB. If the program needs to allocate more memory than is allowed by the current setting of the max heap size, then the system will throw an OutOfMemoryError. Programs that work on very large amounts of data might need to increase this value.

 

-Xprof

The HotSpot VM includes a fairly simple CPU profiling tool. While it isn't a replacement for a full-featured commercial tool, it is quick and easy to use. It also gives some useful information about HotSpot internals that can be interesting.

To use this profiler, simply include the -Xprof option on the command line when you start your program. The profiler option gives you a basic CPU profiler. It does not provide any memory profiling options. When a thread terminates, a report.

This profiler shows the methods that used the most time during that thread's lifetime. The methods are divided into three categories:

  • Interpreted
  • Compiled
  • Stub

Interpreted methods are executed by the bytecode interpreter. Almost 10 percent of the program's time was spent in methods run by the interpreter. However, this is deceptive. You'll notice that there are two columns. The Native column shows the amount of time spent in native C methods called by interpreted methods. Thus, when you break it down that way, this program spends very little time in the interpreter, only a few ticks.

Compiled methods are those that are translated from bytecode to machine code by the compiler. In this case, that is where the program is spending most of its time. Note that it is possible for compiled methods to call out to native C functions, although that doesn't show up in this profile.

The Stub category shows methods called though JNI. The Stub column shows the amount of time it took to set up the call, while the Native column shows the amount of time spent in the native function.

The Global Summary at the end of the profile provides useful information such as how much time the thread spent blocked, and how much time was spent loading classes.

 

-XX Flags

While the flags above are subject to change at any time, the flags in this section are even less reliable. The flags described in this section are for experimentation purposes only. They aren't documented as part of the HotSpot release, and are not supported in any way. Use them at your own risk!

 

Kinds of -XX Flags

There are really two kinds of -XX flags. The first is a Boolean flag. The second is an Integer flag. Boolean flags are used in the following manner:

-XX:<+/-><flagname>

For example, passing the following string as an option to the java command would activate the GoFaster option if one existed.

-XX:+GoFaster

To turn this option off (if it was on by default) you would pass

-XX:-GoFaster

Integer flags are a little different. For example, the following string would set the NumCylinders option to eight.

-XX:NumCylinders=8

 

Flags

 

PrintBytecodeHistogram

Default Value: false

Example Usage:

java -XX:+PrintBytecodeHistogram <yourclass>

This option prints out statistics that show what bytecodes were executed while your program was running. This type of information isn't commonly used when performance tuning typical programs, but might be of interest to researchers.

 

CompileThreshold

Default Value: 1500

Example Usage:

java -XX:CompileThreshold=1000000 <yourclass>

The current implementation of HotSpot usually waits for a method to be executed a certain number of times before it is compiled. Not compiling every method helps startup time and reduces RAM footprint. This option allows you to control that threshold. By increasing the number, you can trade slight reductions in RAM footprint in exchange for a longer period of time before your program reaches peak performance.

 

NewSize

Default Value: 655360

Example Usage:

java -XX:NewSize=196608 <yourclass>

This option allows you to control the default size of the New generation (also known as the nursery) of the HotSpot VM's generational garbage collector. Increasing the amount of new space means that fewer objects will have to be copied to old space. However, a small new space can be scavenged more quickly, and works better with processor caches.



 

Tools

Method Inlining

The Java 2 release of the JVM automatically inlines simple methods at runtime. Method inlining increases performance by reducing the number of method calls your program makes. The Java VM inlining code inlines methods that return constants or only access internal fields.

To take advantage of method inlining you can do one of two things.

  1. Make a method look attractive to the VM to inline.
  2. Manually inline a method if it doesn't break your object model.

Manual inlining in this context means simply moving the code from a method into the method that is calling it.

Automatic VM inlining is illustrated using the following small example:

public class InlineMe 
{

    int counter=0;

    public void method1() 
    {
        for(int i=0;i<1000;i++)
        addCount();
        System.out.println("counter="+counter);
    }

    public int addCount() 
    {
        counter=counter+1;
        return counter;
    }

    public static void main(String args[]) 
    {
        InlineMe im=new InlineMe();
        im.method1();
    }
}

In the current state the addCount method doesn't look very attractive to the inline detector in the VM because the addCount method returns a value. To find out if this method is inlined, run the compiled example with profiling enabled:

java -Xrunhprof:cpu=times InlineMe

This generates a java.hprof.txt output file. The top ten methods will look similar to this:

CPU TIME (ms) BEGIN (total = 510) 
                       Thu Jan 28 16:56:15 1999
rank self accum  count trace method
 1  5.88%  5.88%    1  25 java/lang/Character.
                            <clinit>
 2  3.92%  9.80% 5808  13 java/lang/String.charAt
 3  3.92% 13.73%    1  33 sun/misc/
                            Launcher$AppClassLoader.
                            getPermissions
 4  3.92% 17.65%    3  31 sun/misc/
                            URLClassPath.getLoader
 5  1.96% 19.61%    1  39 java/net/
                            URLClassLoader.access$1
 6  1.96% 21.57% 1000  46 InlineMe.addCount
 7  1.96% 23.53%    1  21 sun/io/
                            Converters.newConverter
 8  1.96% 25.49%    1  17 sun/misc/
                            Launcher$ExtClassLoader.
                            getExtDirs
 9  1.96% 27.45%    1  49 java/util/Stack.peek
10  1.96% 29.41%    1  24 sun/misc/Launcher.<init>

If you change the addCount method to no longer return a value, the VM will inline it for you at runtime. To make the code inline friendly replace the addCount method with the following:

public void addCount() 
{
    counter=counter+1;
}

And run the profiler again:

java -Xrunhprof:cpu=times InlineMe

This time the java.hprof.txt output should look different. The addCount method has gone. It has been inlined!

CPU TIME (ms) BEGIN (total = 560) 
                       Thu Jan 28 16:57:02 1999
rank self  accum  count trace method
 1  5.36%  5.36%    1  27 java/lang/
                            Character.<clinit>
 2  3.57%  8.93%    1  23 java/lang/
                            System.initializeSystemClass
 3  3.57% 12.50%    2  47 java.io.PrintStream.<init>
 4  3.57% 16.07% 5808  15 java/lang/String.charAt
 5  3.57% 19.64%    1  42 sun/net/www/protocol/file/
                            Handler.openConnection
 6  1.79% 21.43%    2  21 java.io.InputStreamReader.fill
 7  1.79% 23.21%    1  54 java/lang/Thread.<init>
 8  1.79% 25.00%    1  39 java.io.PrintStream.write
 9  1.79% 26.79%    1  40 java/util/jar/
                            JarFile.getJarEntry
10  1.79% 28.57%    1  38 java/lang/Class.forName0

 

Streamlined synchronization

Synchronized methods and objects have until Java 2 always incurred an additional performance hit as the mechanism used to implement the locking of this code used a global monitor registry which was only single threaded in some areas such as searching for existing monitors. In the Java 2 release, each thread has a monitor registry and so many of the existing bottlenecks have been removed.

If you have previously used other locking mechanisms because of the performance hit with synchronized methods it is now worthwhile re-visiting this code and incorporating the new Java 2 streamlined locks.

In the following example which is creating monitors for the synchronized block you can achieve a 40% speed up. Time taken was 14ms using JDK 1.1.7 and only 10ms with Java 2 on a Sun Ultra 1.

class MyLock 
{

  static Integer count=new Integer(5);
  int test=0;

  public void letslock() 
  {
     synchronized(count) 
     {
        test++;
     }
  }
}

public class LockTest 
{

  public static void main(String args[]) 
  {

     MyLock ml=new MyLock();
     long time = System.currentTimeMillis();

     for(int i=0;i<5000;i++ ) 
     {
       ml.letslock();
     }
     System.out.println("Time taken=" + (System.currentTimeMillis()-time));
  }
}

 

Java Hotspot

The Java HotSpot VM is Sun Microsystem's next-generation virtual machine implementation. The Java HotSpot VM adheres to the same specification as the Java 2 VM, and runs the same byte codes, but it has been re-engineered to leverage new technologies like adaptive optimization and improved garbage collection models to dramatically improve the speed of the Java VM.

 

Adaptive optimization

The Java Hotspot does not include a plug-in JIT compiler but instead compiles and inline methods that appear it has determined as being the most used in the application. This means that on the first pass through the Java bytecodes are interpreted as if you did not have a JIT compiler present. If the code then appears as being a hotspot in your application the hotspot compiler will compiler the bytecodes into native code which is then stored in a cache and inline methods at the same time. See the inlining section for details on the advantages to inlining code.

One advantage to selective compilation over a JIT compiler is that the byte compiler can be spend more time generating highly optimized for the areas that would benefit from the optimization most. The compiler can also avoid compiling code that may be best run in interpreted mode.

Earlier versions of the Java HotSpot VM were not able to optimize code that was not currently in use. The downside to this is if the application was in a huge busy loop the optimizer would not be able to compile the code for area until the loop had finished. Later Java Hotspot VM releases use on-stack replacement, meaning that code can be compiled into native code even if it is in use by the interpreter.

The third area of improvement is to remove the perception of garbage collection pauses by staggering the compaction of large free object spaces into smaller groups and compacting them incrementally.

 

Fast Thread Synchronization

The Java HotSpot VM also improves existing synchronized code. Synchronized methods and code blocks have always had a performance overhead when run in a Java VM. The Java HotSpot implements the monitor entry and exit synchronization points itself and does not depend on the local OS to provide this synchronization. This results in a large speed improvement especially to often heavily synchronized GUI applications.

 

Just-In-Time Compilers

The simplest tool used to increase the performance of your application is the Just-In-Time (JIT) compiler. A JIT is a code generator that converts Java bytecode into native machine code. Java programs invoked with a JIT generally run much faster than when the bytecode is executed by the interpreter. The Java Hotspot VM removes the need for a JIT compiler in most cases however you may still find the JIT compiler being used in earlier releases.

The JIT compiler was first made available as a performance update in the Java Development Kit (JDK) 1.1.6 software release and is now a standard tool invoked whenever you use the java interpreter command in the Java 2 platform release. You can disable the JIT compiler using the -Djava.compiler=NONE option to the Java VM. This is covered in more detail at the end of the JIT section.

How do JIT Compilers work?

JIT compilers are supplied as standalone platform-dependent native libraries. If the JIT Compiler library exists, the Java VM initializes Java Native Interface (JNI) native code hooks to call JIT functions available in that library instead of the equivalent function in the interpreter.

The java.lang.Compiler class is used to load the native library and start the initialization inside the JIT compiler.

When the Java VM invokes a Java method, it uses an invoker method as specified in the method block of the loaded class object. The Java VM has several invoker methods, for example, a different invoker is used if the method is synchronized or if it is a native method.

The JIT compiler uses its own invoker. Sun production releases check the method access bit for value ACC_MACHINE_COMPILED to notify the interpreter that the code for this method has already been compiled and stored in the loaded class.

When does the code become JIT compiled code?

When a method is called the first time the JIT compiler compiles the method block into native code for this method and stored that in the code block for that method.

Once the code has been compiled the ACC_MACHINE_COMPILED bit, which is used on the Sun platform, is set.

How can I see what the JIT compiler is doing?

The _JIT_ARGS environment variable allows simple control of the Sun Solaris JIT compiler. Two useful values are trace and exclude(list). To exclude the methods from the InlineMe example and show a trace set _JIT_ARGS as follows:


Unix:
export _JIT_ARGS="trace exclude(InlineMe.addCount 
                               InlineMe.method1)"

$ java InlineMe                                               
Initializing the JIT library ...
DYNAMICALLY COMPILING java/lang/System.getProperty 
                                  mb=0x63e74
DYNAMICALLY COMPILING java/util/Properties.getProperty 
                                  mb=0x6de74
DYNAMICALLY COMPILING java/util/Hashtable.get 
                                  mb=0x714ec
DYNAMICALLY COMPILING java/lang/String.hashCode 
                                  mb=0x44aec
DYNAMICALLY COMPILING java/lang/String.equals 
                                  mb=0x447f8
DYNAMICALLY COMPILING java/lang/String.valueOf 
                                  mb=0x454c4
DYNAMICALLY COMPILING java/lang/String.toString 
                                  mb=0x451d0
DYNAMICALLY COMPILING java/lang/StringBuffer.<init> 
                                  mb=0x7d690
 <<<< Inlined java/lang/String.length (4)


Notice that inlined methods such as String.length are exempt. The String.length is also a special method as it is normally compiled into an internal shortcut bytecode by the Java Interpreter. When using the JIT compiler these optimizations provided by the Java Interpreter are disabled to enable the JIT compiler to understand which method is being called.

How to use the JIT to your advantage

The first thing to remember is that the JIT compiler achieves most of its speed improvements the second time it calls a method. The JIT compiler does compile the whole method instead of interpreting it line by line which can also be a performance gain for when running an application with the JIT enabled. This means that if code is only called once you will not see a significant performance gain. The JIT compiler also ignores class constructors so if possible keep constructor code to a minimum.

The JIT compiler also achieves a minor performance gain by not pre-checking certain Java boundary conditions such as Null pointer or array out of bounds exceptions. The only way the JIT compiler knows it has a null pointer exception is by a signal raised by the operating system. Because the signal comes from the operating system and not the Java VM, your program takes a performance hit. To ensure the best performance when running an application with the JIT, make sure your code is very clean with no errors like Null pointer or array out of bounds exceptions.

You might want to disable the JIT compiler if you are running the Java VM in remote debug mode, or if you want to see source line numbers instead of the label (Compiled Code) in your Java stack traces. To disable the JIT compiler, supply a blank or invalid name for the name of the JIT compiler when you invoke the interpreter command. The following examples show the javac command to compile the source code into bytecodes, and two forms of the java command to invoke the interpreter without the JIT compiler.

  javac MyClass.java
  java -Djava.compiler=NONE MyClass

or

  javac MyClass.java
  java -Djava.compiler="" MyClass

Third-Party Tools

Some of the other tools available include those that reduce the size of the generated Java class files. The Java class file contains an area called a constant pool. The constant pool keeps a list of strings and other information for the class file in one place for reference. One of the pieces of information available in the constant pool are the method and field name.

The class file refers to a field in the class as a reference to an entry in the constant pool. This means that as long as the references stay the same, it does not matter what the values stored in the constant pool are. This knowledge is exploited by several tools that rewrite the names of the field and methods in the constant pool into shortened names. This technique can reduce the class file by a significant percentage with the benefit that a smaller class file means a shorter network download.

 

Home