Showing posts with label optimization. Show all posts
Showing posts with label optimization. Show all posts

Thursday, 22 December 2011

Optimizing and Speeding up the code in Java

Finalizers: object that overwrites the finalize() method (“Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.”) is slower!(for both allocation and collection) if it’s not a must, do clean ups in other ways ( e.g. in JDBC close the connection using the try-catch-finally block instead)

New is expensive: creating new heavy object() on the heap is expensive!, it’s recommended to recycle old objects (by changing their fields) or use the flyweight design pattern.

Strings : (1) Strings are immutable which mean that upon usage of the + operator between 2 strings the JVM will generate a new String(s1+s2) on the heap (expensive as I just mentioned), in order to avoid that, it’s recommended to use the StringBuffer.(Update) since JDK 1.5 was introduced  StringBuilder is a better option than Stringbuffer in a single-threaded environment.

(2) Don’t convert your strings to lower case in order to compare them, use String.equalIgnoreCase() instead.

(3) String.startswith() is more expensive than String.charat(0) for the first character.

Inline method: inline is a compiler feature, when you call a method from anywhere in your code, the compiler copies the content of the inline method and replace the line that calls the method with it.

Obviously,It saves runtime time: (1) there is no need to call a method (2) no dynamic dispatch.

In some languages you can annotate a method to be inline, yet in Java it’s impossible, it’s the compiler decision.

the compiler will consider inline a method if the method is private.

My recommendation is to search in your code for methods that are heavily used(mostly in loops) and annotate those method as private if possible.

Don’t invent the wheel: the java api is smart and sophisticated and in some cases use native implementation, code that you probably can’t compete with. unless you know what you are doing (performance wise) don’t rewrite methods that already exists in the java API. e.g. benchmarks showed that coping and array using a for loop is at least n/4 times slower than using System.arraycopy()

Reflection: reflection became much faster for those of you who use the most recent JVMs, yet using reflection is most certainly slower than not using it. which mean that you better avoid reflection if there is no need.

Synchronization: Some data structures auto-support concurrency, in case of a single thread application don’t use those to avoid overhead e.g. use ArrayList instead of a Vector

Multithreads: in case of a multi processor use threads, it will defiantly speed up your code, if you are not a thread expert some compilers know how to restructure your code to thread automatically for you. you can always read a java threads tutorial as well

Get familiar with the standard data structures:   e.g. if you need a dast for puting and retriving objects use HashMap and not an ArrayList. (O(1))

Add an id field, for faster equals(): object that contains many fields are hard to compare ( equals() wise), to avoid that add an id(unique) field to your object and overwrite the equals() method to compare ids only.

Be careful, In case  your code already works, optimizing it is a sure way to create new bugs and make your code less maintainable!

it’s highly recommended to time your method before and after an optimization.

Monday, 20 June 2011

Array iteration optimization in Java

The problem
I am working on a project right now which involves lots of loops that look like:

for( int x = 0; x < size; x++ ) {
for( int y = 0; y < size; y++ ) {
for( int z = 0; z < height; z++ ) {
if( somearray[x][y][z] == somevalue) {
// do something
}
}
}
}

Writing out these loops by hand got tedious, error-prone, high-maintenance, and makes the code longer.
If I was writing in C++, I could macro it out.
In Java, for reasons I tend to agree with, there are no macros, not an option. Same deal in C#, as far as I know.
Idea One: anonymous classes
My first idea was to write a class which would use an anonymous class to call back into my code. I figured one could use it like this:
new Iterator(startVector3i, endVector3i).iterate( new Callback(){
public void callback(Vector3i next ){
// do stuff here
}
));

Technically this is possible, except the code inside has no access to our local variables in our calling method, which makes it not terribly useful I feel.

Discovery: using an iterator class surprisingly slow

Next, I made an iterator class that worked like this:
ArrayIterator iterator = new ArrayIterator(startVector3i,endVector3i);
while( iterator.next() ){
if( somearray[iterator.x][iterator.y][iterator.z] == somevalue ) {
// do something
}
}

This took a long time to execute. Compared to the bog-standard nested for-loops we started with, it took 20 times longer to execute!

Why?

Deduction: java optimizes processor cache requests in nested for loops

It baffled me why this approach was so slow. Surely a method call is not so expensive?

I tried all sorts of different performance tests, and in the end found the following very specific code sample:

for( int x = 0; x < size; x++ ) {
for( int y = 0; y < size; y++ ) {
for( int z = 0; z < height; z++ ) {
if( somearray[x][y][z] == somevalue) {
// do something

This runs quickly.

for( int x = 0; x < size; x++ ) {
for( int y = 0; y < size; y++ ) {
for( int z = 0; z < height; z++ ) {
if( wrapperObject.getArrayValueAt(x,y,z) == somevalue) {
// do something
This runs 20 times slower, even though normal simple method calls were not particularly expensive I found.
My conclusion is that when we iterate over an array with an obvious in-lined for loop, java/jvm/processor has enough information available to realize it can optimize by fetching a batch of values from the array all at once.
When the array access is not directly inside the nested for loop, this doesn’t work.
So, my conclusion is that it seems any iterative access to large arrays needs to be explicitly inlined with the iterating loop in the code.
Edit: found a relevant sun wiki page that I think explains this effect
http://wikis.sun.com/display/HotSpotInternals/RangeCheckElimination
Basically, a bunch of range checks are carried out on array access, and when the access is done in a for loop, many of these checks are eliminated, where the loop body is inlined.

Friday, 20 May 2011

ArrayList speed optimization

Lets see how we can increase the speed while processing the ArrayList. The default size for a Java ArrayList class at the initial stage is 10. When an ArrayList operation reaches its maximum capacity which is 10, it increases its capacity by approximately half. A lot of time gets consumed in this case. Lets see why suppose you are adding elements to the ArrayList and if it reaches to 10 then it creates bigger arraylist with size 15 (approx.) and copies both new and old data to it.
So if we are knowing the size in advance then it is very useful to initialize the arraylist with that size to avoid performance overhead.

Lets see how much difference it makes if specify initial size in advance.

public class ArrayListSpeedTest {
private static int size = 5000000;

public ArrayListSpeedTest() {

ArrayList dynamicArrayList = new ArrayList();
ArrayList staticArrayList = new ArrayList(size);

// Lets check how much time it took to load dynamic arraylist size.
long start = System.currentTimeMillis();
loadData( dynamicArrayList );
System.out.println("Dynamic array list took ("+ (System.currentTimeMillis()-start)+ " mS) to load the data.");

// sLets check how much time it took to load static arraylist size.
start = System.currentTimeMillis();
loadData( staticArrayList );
System.out.println("Static Array list took (" +(System.currentTimeMillis()-start) +" mS) to load the data.");

}

private void loadData(ArrayList target) {
for(int i=0; i< size; i ++ ) {
target.add(" test ");
}
}

public static void main(String[] args){
new ArrayListSpeedTest();
}
}

 

Output:

Dynamic array list took (231 mS) to load the data.
Static Array list took (67 mS) to load the data.