Home Company Services Experience Process Articles FAQs Contact Us

Java Performance Topics


1.    Java Performance Issues

Byte code interpretation

Since byte code is not machine native language, the mapping from byte code to executable bits at runtime costs extra CPU cycles and memories. In real world, however, bad design and careless coding usually cause more problems.

Java virtual machine

This extra layer and associated indirection obviously will cost more CPU cycles. Plus, Java VM prevents you from taking advantage of the CPU registers. Again, bad design and careless coding usually make the issue worse that it shall be.

Garbage collection

Garbage collection is usually done periodically at the background with low-priority thread, that is, when there are no higher priorities threads, including most likely the application threads, are running. This leads to two problems: (1) Cannot predict or control when garbage collection will happen; (2) Accumulated memory cleanup and release make the impact bigger than the scattered way.

Strong encapsulation

In Java all variables and methods are defined in the scope of classes and interfaces. There are no such things as global variables or methods. This brings some indirection cost when accessing constant variables.

Deep class hierarchy

The powerful features and flexibility of Java language have a side effect: classes in Java programs tend to extend multiple layers of super classes and implement many numbers of interfaces. When one class is loaded into Java VM at runtime, all its super classes and interfaces must be loaded too. Deep class hierarchy can really surprise you in terms of how long it may take to load just “one” class.

The “Thread” class

Java’s way of using one class (the Thread class) to handle all threading issues makes programming easier but also takes away much flexibility. Since the lock is at the thread object level, when one synchronized method is running, none of the other synchronized methods can be executed. Plus, thread local variables need to be refreshed from the “main” memory variables before the synchronized method starts and any changes need to reflect back to “main” memory variables when the synchronized method returns.

Dynamic binding

Other than final methods, all methods are encoded as strings in the class files and bound at runtime on demand. String parsing and method locating lead to many runtime overhead.

Hidden Checking

Java adds several safety guides to make sure programs run safely, e.g. boundary checking for array, range checking for Vector. While they bring in some intelligence, the extra smartness always comes with extra cost.

2.    Performance Tuning Tips

Variables

(1)   Minimize the usage of temporary objects, especially in loops and frequently used methods.

(2)   Avoid using new objects. Try to reuse existing objects whenever possible.

(3)   Defer initialization of local variables until the last minute. For example, don’t define the local variable if it will be used after a logical branch. The ended branch may not use the variable at all.

(4)   Class variables are more expensive to create and manipulate than instance variables.

Multithreading

(1)   Unless on a multi-processor machine, don’t use multithreading whenever possible.

(2)   Minimize the usage of synchronized methods.

(3)   Use notify instead of notifyAll because notifyAll needs to locate all the threads that are waiting on the object and notify them all.

String manipulation

(1)   Use StringBuffer instead of the string concatenation operation (+).

(2)   Use String for read-only string and string that will be shared. Avoid StringBuffer in this case.

(3)   Avoid using string for searching or indexing. Use integers instead.


Jerry Zhong, June 2000.