Friday, December 18, 2009

Performance tuning for Java developers

Java Performance Tuning and Java Optimization Tips

Hi, I have taken this content from "http://www.glenmccl.com/jperf/index.htm" site.

This blog illustrates practical ways you can improve JavaTM performance tuning and Java efficiency techniques. These techniques focus on Java language and library features. Performance is defined to include both speed and space issues, that is, how to make your programs run faster, while using less memory and disk space. Many of the techniques are illustrated by code examples.

This blog raises a variety of performance issues, and gives some hard numbers about how specific performance improvements work out. The ultimate aim of the paper is to promote awareness of Java performance issues, so that you can make appropriate design and implementation choices for specific applications.

PDF Free Download

Table of Contents

Introduction

When to Worry About Performance
Performance Issues Not Covered in This Paper
Just-in-Time Compilers and Java Virtual Machines
Environment and Tools Used in Code Examples
How Examples Were Timed
Performance Analysis Tools
Web Site

Classes

Default Constructors
Constructor Hierarchies
Class and Instance Initialization
Recycling Class Instances

Methods

Inlining
Final Methods
Synchronized Methods
Inner Classes

Strings

Strings are Immutable
Accumulating Strings Using char[] Arrays
Using == and String.equals() to Compare Strings
Interning Strings
Obtaining the Length of a String
Using toCharArray()
Converting Strings to Numbers

Input and Output

Buffering
BufferedReader
Formatting
Obtaining File Information

Libraries

System.arraycopy()
Vector vs. ArrayList
Setting Initial Array Capacity
ArrayList vs. LinkedList
Programming in Terms of Interfaces

Size

.class File Size
Wrappers
Garbage Collection
SoftReference
BitSet
Sparse Arrays

1. Class and Instance Initialization

When an instance of a class is created using new, initialization of the class's instance variables (variables unique to each instance) must be done. By contrast, class variables (those declared static, and shared across instances) need only be initialized once, conceptually at program invocation time . The difference between these types of initialization is quite important, as this example illustrates:

// class initialization

public class cls_init1 {
static class Data {
private int month;
private String name;
Data(int i, String s) {
month = i;
name = s;
}
}
Data months[] = {
new Data(1, "January"),
new Data(2, "February"),
new Data(3, "March"),
new Data(4, "April"),
new Data(5, "May"),
new Data(6, "June")
};
public static void main(String args[]) {
final int N = 250000;
cls_init1 x;
Timer t = new Timer();
for (int i = 1; i <= N; i++)
x = new cls_init1();
t.print("data declared non-static");
}
}
// Timer class  public class Timer { 
long t;
// constructor 
public Timer() {
reset(); 
}
// reset timer 
public void reset() {
t = System.currentTimeMillis();
}
// return elapsed time
public long elapsed() { 
return System.currentTimeMillis() - t;
} 
// print explanatory string and elapsed time
public void print(String s) {
System.out.println(s + ": " + elapsed());
}
} 

This example takes 4627 units of time to run. However, if we look closely at this class, there is a potential inefficiency. The month number/name data found in months[] is an instance variable of the class, that is, a copy of the data is found in every instance of the class. Structuring the data in this way doesn't make sense, in that the number/name data never changes, and is the same across all class instances.

So we can change the program slightly, to turn the number/name data into a class variable, with a single copy across all instances:

// class initialization

public class cls_init2 {
static class Data {
private int month;
private String name;
Data(int i, String s) {
month = i;
name = s;
}
}
static Data months[] = {
new Data(1, "January"),
new Data(2, "February"),
new Data(3, "March"),
new Data(4, "April"),
new Data(5, "May"),
new Data(6, "June")
};
public static void main(String args[]) {
final int N = 250000;
cls_init2 x;
Timer t = new Timer();
for (int i = 1; i <= N; i++)
x = new cls_init2();
t.print("data declared static");
} } 
// Timer class  public class Timer {
long t;      
// constructor   
public Timer() { 
reset();
}      
// reset timer
public void reset() {     
t = System.currentTimeMillis();
}
// return elapsed time
public long elapsed() {
return System.currentTimeMillis() - t;
}       
// print explanatory string and elapsed time
public void print(String s) {
System.out.println(s + ": " + elapsed());
}
} 

This program requires 421 units of time to run, a saving of 10-1 over the first approach. Moreover, it saves a lot of space per class instance as well. As a general rule, it's worth "factoring out" methods that do not operate on unique data in a class instance, and variables that are not unique to an instance, and making both methods and variables static, that is, shared across all instances.

2. Inner Classes

An interesting situation with method call overhead arises when you use inner classes. The inner class specification says that a private method of a class A can be used by a class B, if A encloses B. That is, if B is a class defined within A, it can call A's private methods. Here is an example:

// methods and inner classes

public class meth_inner {
private void f() {}
class A {
A() {
f();
}
}
public meth_inner() {
A a = new A();
}
public static void main(String args[]) {
meth_inner x = new meth_inner();
}
}

A is an inner class defined within meth_inner, and A's constructor calls a private method f() defined in meth_inner. Because the Java Virtual Machine has restrictions on calling private members from outside of their class, a special access method is generated by the compiler and added internally to the meth_inner class. This method has a name access$0(), and it in turns calls f(). In other words, a method is generated that can be called from outside of meth_inner, and grant access to a private method of meth_inner. So when f() is called above, a generated method access$0() is called, and it in turn calls f().

If you use the JDK utility program that disassembles .class files, by saying:

$ javap -c meth_inner

the output includes the following method definition:

Method void access$0(meth_inner)
0 aload_0
1 invokespecial #7 
4 return

This is the body of the generated method.

You can avoid this overhead by avoiding use of private members in a class, assuming the class has inner classes that use those members. Obviously, however, there may be other reasons why private members are more important than the overhead associated with these generated methods.

3. Converting Strings to Numbers

Suppose you have a string like "12.34" that represents a number, and you'd like to convert it to numeric form. How expensive is such an operation? One way to find out is by writing a small program that creates a Double (a wrapper class for double), from either a string or a number.

The program looks like this:

// converting strings to numbers

public class str_double {
public static void main(String args[]) {
final int N = 100000;
Double d;

// construct Double from string

Timer t = new Timer();
for (int i = 1; i <= N; i++)
d = new Double("12.34");
t.print("as string");      
// construct Double from number
t.reset();
for (int i = 1; i <= N; i++)
d = new Double(12.34);
t.print("as number");
} } 
// Timer class  public class Timer {
long t;
// constructor
public Timer() {
reset();  
}
// reset timer
public void reset() {
t = System.currentTimeMillis();
}
// return elapsed time
public long elapsed() {
return System.currentTimeMillis() - t;
}         // print explanatory string and elapsed time
public void print(String s) {
System.out.println(s + ": " + elapsed());
}
} 

Creating a Double from a string takes about 15 times as long as from a number. This difference starts to make sense when you consider all the processing that must go on when converting to a number, including operations such as retrieving characters from the string, multiplication, handling the decimal point, and so on.

Often you have no choice but to do conversion of strings to numbers, but it's worth keeping in mind the expense of this operation.

Contact the Author

Please send comments on this blog to "deepakmodi2006@gmail.com".

No comments:

Post a Comment