1. Introduction 2. When to think of Performance 3. JVM’s and JIT Compilers 4. Default constructors 5. Constructor Hierarchies 6. Instance variables Vs Class(static) variables 7. Recycling Objects 8. Methods 8.1 Inlining Methods 8.2 Final Methods 9. Thread Synchronization 10. Inner classes 11. String and StringBuffer 11.1 Accumulating data Using char[] Arrays 11.2 Using = = and equals() with Strings 11.3 Using the length() of a String 11.4 Using toCharArray() 11.5 Converting strings and double to Wrapper objects 12. I/O Streams 12.1 Using Chaining 13. Formatting 14. Getting File Information(Disk access) 15. Libraries 15.1 java.util package 15.2 Vector vs. ArrayList 15.3 Setting Initial Array Capacity 15.4 Setting Initial Array Capacity 15.4 ArrayList vs. LinkedList 16. Programming in Terms of Interfaces 17. Wrappers 18. Garbage Collection
1. Java Performance Tips: Introduction
Performance has been an important issue for Java developers with any language. Performance includes both speed of execution and the memory, the process, occupies. That is, how to make our program run faster and at the same time using less memory and disk space. There is no correct formula on performance because different applications have different characteristics and bottlenecks and also performance differs across different hardware, operating systems and development tools like virtual machines and compilers. This training provides how tricks such as minimizing object creation and replacing strings with arrays can really pay off in improving your code’s performance. The aim of the two days discussion is to promote the awareness of performance issues in Java so that we can make suitable design and implementation options for specific tasks. Java Performance Tuning offers common-sense advice about what to tune and what to leave alone, emphasizing techniques that provide big performance gains with minimal code
2. Java Performance Tips: When to think of Performance
Programmer should bother not only the performance but also should consider the issues like quality, readability and maintainability etc. Some techniques may ultimately lead to more complex code and should be considered only when required. Sometimes, the performance issues must be considered at design phase itself. If poor performance is built into the architecture itself, it becomes very difficult to tune the performance. For example, choosing an N*N sort of algorithm instead of more efficient N*log(N) one and using many super classes(subclass constructor invokes all its super class constructors) is a bad design. Suppose the code is designed to read the data in a number of chunks and is chunk is processed by many constructors of the super classes and such code requires complete redesign which becomes practically very difficult and time consuming. For this reason, it is important to keep in mind, the performance issues in the design phase itself.
3. Java Performance Tips: JVM’s and JIT Compilers
The latest versions of Java tools offer various approaches to increase performance compared to the original JDK1.0 version of byte code interpretation. The tools approaches includes compiling(interpretation stage) the bytecode into machine code at runtime. Some areas where performance enhancement can be done include a) method inlining and adaptive inlining where methods are inlined basing on their use and number of calls b) synchronization c) compiling Java source code into native code of the operating system etc. As a designer, examining and choosing of appropriate tools is also important. Using a JVM with built-in JIT compiler increases the performance 40 times. Choosing the right tool is very important rather than trying to tune the code for performance aspects.
A small Clock program developed to know the performance:
public class Clock
{
long time;
public Clock()
{
setZero();
}
public void setZero()
{
time = System.currentTimeMillis();
}
public long timeTaken()
{
return System.currentTimeMillis() - time;
}
public void printTime(String str)
{
System.out.println(str + ": " + timeTaken());
}
public static void main(String args[])
{
Clock c1 = new Clock();
for(int i = 0; i < 1000000; i++) { }
c1.printTime("Time tiken for 1000000 iterations");
c1.setZero();
for(int i = 0; i < 100000000; i++) { }
c1.printTime("Time tiken for 100000000 iterations");
}
}
The above screen shows different results when executed different times. It is because a number processes may be running right now on your system, some of which may be in pause, working or stopped etc. Also it depends on the availability of JVM free time. The above Clock program is used in every program to know the performance.
4. Java Performance Tips: Default constructors
Observe the code:
public class Demo
{
public static void main(String args[])
{
Demo d1 = new Demo();
}
}
In the above code, we created an object of Demo class, d1, by accessing the default constructor; but the default constructor is not provided by the programmer. If the programmer does not provide his own default constructor, the JVM creates one and supplies and this takes time. So, always provide a default constructor in your program.
5. Java Performance Tips: Constructor Hierarchies
Suppose we have the following class hierarchy:
class A {...}
class B extends A {...}
class C extends B {...}
As discussed above, when we create an object of class C, its default constructor calls the default constructors of all super classes up to class Object. This takes some time. For this reason, involve less super classes in the hierarchy.
6. Java Performance Tips: Instance variables Vs Class(static) variables
When the data is the same used by all the objects of the class, better declare the variables as static. Static variables are initialized only once. By declaring non-static, we must assign the value for each object separately which is time consuming and takes more space. The difference makes a lot as the following program explains:
public class StaticVsInstance
{
int rno; // declare static
String name; // declare static and see the difference
public void call()
{
rno = 35;
name = "S N Rao";
}
public static void main(String args[])
{
StaticVsInstance svi[] = new StaticVsInstance[200000];
Clock c1 = new Clock();
for(int i = 0; i < 200000; i++)
{
svi[i] = new StaticVsInstance();
svi[i].call();
}
c1.printTime("Non-static variables");
}
}
If the variables are not static, 2,00,000 objects will have their own memory locations for rno and name. If static, only one memory location is created and shared by all 2,00,000 objects of the class.
7. Java Performance Tips: Recycling Objects
Instead of creating a number of objects for a single class, if an object job is over, the same object can be reused a number of times as follows:
Demo d1 = new Demo(); // create an object initially
If the job of d1 is over:
d1 = null; // this is, in fact, not required
d1 = new Demo();
Now the object d1 can be used for new data.
8. Methods
There exists an inherent overhead associated with calling methods. These overheads includes actual transfer of control to the called method, parameters passing, return value return to the calling method and establishment of the called method’s stack frame for local variable storage. This type of overheads exists in other programming languages also.
8.1 Java Performance Tips: Inlining Methods
The most efficient style to deal with method call overhead is method inlining. The method inlining can be done by the programmer or a compiler also implicitly. Inlining is nothing but writing the called method code in the calling method itself. Observe the following example:
// Not Inline code
public class MethodInlining
{
public int getMaximum(int a, int b)
{
return (a > b ? a : b);
}
public static void main(String args[])
{
MethodInlining mi = new MethodInlining();
Clock c1 = new Clock();
for( int i = 0; i < 10000000; i++)
{
int c = mi.getMaximum(10,20);
}
c1.printTime("Not Inline");
}
}
Now shift the Inline code. Shift the calling method code into the calling method main itself.
// Inline code
public class MethodInlining
{
public static void main(String args[])
{
MethodInlining mi = new MethodInlining();
Clock c1 = new Clock();
int a = 10, b = 20;
for( int i = 0; i < 10000000; i++)
{
int c = a > b ? a : b;
}
c1.printTime("Inline");
}
}
With inline code, the performance is improved 2 to 3 times.
8.2 Java Performance Tips: Final Methods
The compiler places final methods as inline methods because subclass methods need not be called. Final methods cannot be overridden by subclass.
public final display() { }
The same style can be applied to classes also by declaring them final. A final class cannot be inherited and thereby all the methods of a final class are implicitly final.
public final class Demo { }
If a subclass method is assigned to a super class, the super class will call subclass overridden method. If the class is not declared as final, the JRE has to check its subclasses whether the super class method is overridden or not. If overridden, it must call the subclass method. For the dynamic method dispatch, it takes a long time and is a overhead. It is very difficult to inline subclass methods as which subclass method is to be called is decided at runtime. So, when the code does not include method overriding, simply declare the super class method as final and also when you do not extend your class, declare it as final.
Thanks Nageswara Rao, It is too helpful for writing best code.
Exlent notes
Thanks a lot for the informative articles.
Hey Nageshwar, Thanks a lot for sharing this tutorial. This is really very useful.
Thank your support. Tell your friends also to derive knowledge out of it.