Java performance and optimization - Speed
What tools are available?
There are very good tools known as profilers. Using them, you can profile the performance of Java application and measure the performance of methods at line or function level, or time methods. They access debug data stored in class files to collect line-by-line performance data to display in the Annotated Source window. Usually, you must compile your class file appropriately to generate the debug data.
Visual Quantify, from Rational Software.
OptimizeIt, from Intuitive Systems.
VTune, from Intel.
How to improve speed?
Here is a list of tips.
Bytecode optimization using a good compiler
Compiler perform some optimization. For example, with the jdk 1.1, you can use java -0 to do the following:
- Constant folding -- the compiler resolves any constant expressions such that i = (2 *2) compiles to i = 4.
- Limited dead code elimination -- no code is produced for statements like if(debug) i = 1.
Native methods
We have a article on native methods. You will get the speed of C, but loose portability.
Use "Just-in-time" compilers
The following example uses Strings and integers:
import java.lang.StringBuffer;
class Main
{
public static void main(String [] argv) {
String a="String 1";
String c;
for (int i=0;i<100000;i++) c=a+i;
}
Using jdk 1.1.4 , it takes 47s. With Microsoft VM (SDK 2.0), it only takes 5s! Just-in-Time compilers improve performance a lot!
Avoid exception handling when it's not necessary
try/catch blocks may be very slow. For example, if you try to handle an exception that may occur only one time in a loop, rewrite your code. Find another way to handle errors instead of using try/catch blocks to compile cleanly!
Strings and Stringbuffers
Let's consider an example:
String a="String 1";
String b="String 2";
String c=a+b;
Each time you use the + operator with two strings, the compiler creates a new StringBuffer object with the content of the first string, create a new string object with the second string and concatenates it using the append method with the previous StringBuffer object. Then, this StringBuffer object is converted into a String. This is the bytecode generated by Microsoft SDK 2.0:
9: String a="String 1";
00000000 ldc "String 1"
00000002 astore_1 a
10: String b="String 2";
00000003 ldc "String 2"
00000005 astore_2 b
11: String c=a+b;
00000006 new java/lang/StringBuffer
00000009 dup
0000000a invokenonvirtual java/lang/StringBuffer.
0000000d aload_1 a
0000000e invokevirtual java/lang/StringBuffer.append(java/lang/String)
00000011 aload_2 b
00000012 invokevirtual java/lang/StringBuffer.append(java/lang/String)
00000015 invokevirtual java/lang/StringBuffer.toString()
00000018 astore_3 c
Now let's follow with this optimization:
String a="String 1";
String b="String 2";
String c=new StringBuffer(a).append(b).toString();
9: String a="String 1";
00000000 ldc "String 1"
00000002 astore_1 a
10: String b="String 2";
00000003 ldc "String 2"
00000005 astore_2 b
11: String c=new StringBuffer(a).append(b).toString();
00000006 new java/lang/StringBuffer
00000009 dup
0000000a aload_1 a
0000000b invokenonvirtual java/lang/StringBuffer.
0000000e aload_2 b
0000000f invokevirtual java/lang/StringBuffer.append(java/lang/String)
00000012 invokevirtual java/lang/StringBuffer.toString()
00000015 astore_3 c
In this last example, the concatenation is done in 15-7=9 instructions, instead of 12. The difference is that the StringBuffer constructor is called with the "String 1" parameter directly. The difference may be significant within a loop.
Synchronization
Avoid the use of synchronized methods. Picking the whole method is he simplest to use. Anyway, It is very inefficient to hold the lock for the section of code where it is actually not needed. Synchronizing a class because it may be used by multiple thread is also inefficient. It takes some time to get the lock.
I/O
There is a lot of synchronized methods in the JDK1.1 API. Avoid doing I/O in loops, use buffered streams instead such as BufferedInputStream.
Garbage collection
You can improve performance of your Java applications by not creating excess objects to be garbage collected. The smaller heap requirement will keep the amount of virtual memory smaller. It is also less expensive to reuse an existing object than it is to allocate a new copy of that object.
This page was last updated 06 March 1998