Thursday, December 9, 2010

String's

1. Introduction

            In Java strings are objects designed to represent a sequence of characters. Because character strings are commonly used in programs, Java supports the ability to declare String constants and perform concatenation of Strings directly without requiring access to methods of the String class.

 A Java String is read-only and once created the contents cannot be modified.

String buffers support mutable strings. Because String objects are immutable they can be shared

2. Declaring and Allocating Strings


         The String class has 13 different constructors. Only the most common constructors will be presented. For complete information on the String class, access Oracle's Java API page at http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html


The simplest method to create a String object is to enclose the string literal in quotes and assign the value to a String object. Creation of a String through assignment does not require the use of the new operator, for example
                      For example:

                               String str = "abc";    is equivalent to:

     char data[] = {'a', 'b', 'c'};
     String str = new String(data);

              Alternatively, String objects can be created through constructors. The following constructors are supported:

public String()
Constructs a new String with the value "" containing no characters. The value is not null.


public String( String value )
Constructs a new String that contains the same sequence of characters as the specified String argument.

public String( char[] value )
Constructs a new String containing the same sequence of characters contained in the character array argument.

public String(byte[] bytes)
Constructs a new String by decoding the specified array of bytes using the platform's default charset.

public String(StringBuffer buffer)
Allocates new string that contains the sequence of characters currently contained in the string buffer argument.

public String(StringBuilder builder)
Allocates new string that contains the sequence of characters currently contained in the string builder argument.

Here are some more examples of how strings can be used:

     System.out.println("abc");
     String cde = "cde";
     System.out.println("abc" + cde);
     String c = "abc".substring(2,3);
     String d = cde.substring(1, 2);

3. String Concatenation

Work in progress....

Wednesday, December 8, 2010

Singleton

“Design patterns are recurring solutions to design problems.”
Java Design patterns are grouped under three categories:
                1. Creational Patterns
                2. Structural Patterns
                3. Behavioral Patterns
Singleton Pattern being the most commonly used creational design pattern. This design pattern proposes that at any time there can be only one instance of a singleton (object) created by the JVM.

                The class’s default constructor is made private, which prevents the direct instantiation of the object by others (Other Classes). A static modifier is applied to the instance method that returns the object as it without creating an object.
1)   Creating  the normal Singleton class
class Singleton
{
  private static Singleton instance;
  private Singleton()  {  }
  public static Singleton getInstance() 
  {
    if (instance == null)                                     //1
 instance = new Singleton();        //2
    return instance;                                            //3
  }
}
The design of this class ensures that only one Singleton object is ever created. The constructor is declared private and the getInstance() method creates only one object. This implementation is fine for a single-threaded program. However, when multiple threads are introduced, you must protect the getInstance() method through synchronization. If the getInstance() method is not protected, it is possible to return two different instances of the Singleton object.
2)   Creating the Thread-safe getInstance() method

public static synchronized Singleton getInstance()
{
  if (instance == null)                       //1
    instance = new Singleton();      //2
  return instance;                               //3
}
The code in step 2 works fine for multithreaded access to the getInstance() method. However, when you analyze it you realize that synchronization is required only for the first invocation of the method. Subsequent invocations do not require synchronization because the first invocation is the only invocation that executes the code at //2, which is the only line that requires synchronization. All other invocations determine that instance is non-null and return it. Multiple threads can safely execute concurrently on all invocations except the first. However, because the method is synchronized, you pay the cost of synchronization for every invocation of the method, even though it is only required on the first invocation.
In an effort to make this method more efficient, an idiom called double-checked locking was created. The idea is to avoid the costly synchronization for all invocations of the method except the first. The cost of synchronization differs from JVM to JVM. In the early days, the cost could be quite high. As more advanced JVMs have emerged, the cost of synchronization has decreased, but there is still a performance penalty for entering and leaving a synchronized method or block. Regardless of the advancements in JVM technology, programmers never want to waste processing time unnecessarily.
Because only line //2 in step 2 requires synchronization, we could just wrap it in a synchronized block, as shown in step 3:

3)   The getInstance() method
public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {
      instance = new Singleton();
    }
  }
  return instance;
}
The code in step 3 exhibits the same problem as demonstrated with multiple threads and step 1. Two threads can get inside if statement concurrently when instance is null. Then, one thread enters the synchronized block to initialize instance, while the other is blocked. When the first thread exits the synchronized block, the waiting thread enters and creates another Singleton object. Note that when the second thread enters the synchronized block, it does not check to see if instance is non-null.

Double-checked locking

To fix the problem in step 3, we need a second check of instance. Thus, the name "double-checked locking."  Applying the double-checked locking idiom to step 3 results in step 4

4)   Double-checked locking example
public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {  //1
      if (instance == null)          //2
        instance = new Singleton();  //3
    }
  }
  return instance;
}
The theory behind double-checked locking is perfect. Unfortunately, reality is entirely different. The problem with double-checked locking is that there is no guarantee it will work on single or multi-processor machines.

The issue of the failure of double-checked locking is not due to implementation bugs in JVMs but to the current Java platform memory model. The memory model allows what is known as "out-of-order writes" and is a prime reason why this idiom fails.

Out-of-order writes

To illustrate the problem, you need to re-examine line //3 from step 4 above. This line of code creates a Singleton object and initializes the variable instance to refer to this object. The problem with this line of code is that the variable instance can become non-null before the body of the Singleton constructor executes.
Given that the current double-checked locking code does not work, I've put together another version of the code, shown in step 5, to try to prevent the out-of-order write problem.

5)   Attempting to solve the out-of-order write problem
public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {      //1
      Singleton inst = instance;         //2
      if (inst == null)
      {
        synchronized(Singleton.class) {  //3
          inst = new Singleton();        //4
        }
        instance = inst;                 //5
      }
    }
  }
  return instance;
}
Looking at the code in step 5 you should realize that things are getting a little ridiculous. Remember, double-checked locking was created as a way to avoid synchronizing the simple three-line getInstance() method. The code in step 5 has gotten out of hand. In addition, the code does not fix the problem
The code in step 5 doesn't work because of the current definition of the memory model. The Java Language Specification (JLS) demands that code within a synchronized block not be moved out of a synchronized block. However, it does not say that code not in a synchronized block cannot be moved into a synchronized block.
A JIT compiler would see an optimization opportunity here. This optimization would remove the code at //4 and the code at //5, combine it and generate the code shown in step 6:

6)   Optimized code from step 5
public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {      //1
      Singleton inst = instance;         //2
      if (inst == null)
      {
        synchronized(Singleton.class) {  //3
          //inst = new Singleton();      //4
          instance = new Singleton();              
        }
        //instance = inst;               //5
      }
    }
  }
  return instance;
}
The bottom line is that double-checked locking, in whatever form, should not be used because you cannot guarantee that it will work on any JVM implementation. JSR-133 is addressing issues regarding the memory model; however, double-checked locking will not be supported by the new memory model. Therefore, you have two options:
  • Accept the synchronization of a getInstance() method as shown in step 2.
  • Forgot synchronization and use a static field.
  • Use a static inner class and create the static final instance inside the class.
Option 2 is shown in Step 7:
7)   Singleton implementation with static field

class Singleton
{
  private static Singleton instance = new Singleton();

  private Singleton()
  {
    //...
  }
  public static Singleton getInstance()
  {
    return instance;
  }
}
Option 3 is shown in Step 8:
8)   Singleton implementation with static inner class

public class Singleton {
  // Private constructor prevents instantiation from other classes
  private Singleton() {}

  /**
   * SingletonHolder is loaded on the first execution of Singleton.getInstance()
   * or the first access to SingletonHolder.INSTANCE, not before.
   */
  private static class SingletonHolder {
    private static final Singleton INSTANCE = new Singleton();
  }

  public static Singleton getInstance() {
    return SingletonHolder.INSTANCE;
  }
}

Tuesday, December 7, 2010

JVM

Java Virtual Machine

Java Virtual Machine or JVM as its name suggest is a “virtual” computer that resides in the “real” computer as a software process. JVM gives Java the flexibility of platform independence. Let us see first how exactly Java program is created, compiled and executed.


Java Virtual Machine or JVM as its name suggest is a “virtual” computer that resides in the “real” computer as a software process. JVM gives Java the flexibility of platform independence. Let us see first how exactly Java program is created, compiled and executed.



Java code is written in .java file. This code contains one or more Java language attributes like Classes, Methods, Variable, and Objects etc. Javac is used to compile this code and to generate .class file. Class file is also known as “byte code“. The name byte code is given may be because of the structure of the instruction set of Java program. We will see more about the instruction set later in this tutorial. Java byte code is an input to Java Virtual Machine. JVM read this code and interpret it and executes the program.



     Java Virtual Machine like its real counter-part executes the program and generates output. To execute any code, JVM utilizes different components.
JVM is divided into several components like the stack, the garbage-collected heap, the registers and the method area. Let us see diagram representation of JVM.







The Stack
Stack in Java virtual machine stores various method arguments as well as the local variables of any method. Stack also keeps track of each and every method invocation. This is called Stack Frame. There are three registers that help in stack manipulation. They are vars, frame, and optop. This registers points to different parts of current Stack.
There are three sections in Java stack frame:
Local Variables :
The local variables section contains all the local variables being used by the current method invocation. It is pointed to by the vars register.
Execution Environment
The execution environment section is used to maintain the operations of the stack itself. It is pointed to by the frame register.
Operand Stack
The operand stack is used as a work space by byte code instructions. It is here that the parameters for byte code instructions are placed, and results of byte code instructions are found. The top of the operand stack is pointed to by the optop register.

Method Area

This is the area where byte codes reside. The program counter points to some byte in the method area. It always keeps tracks of the current instruction which is being executed (interpreted). After execution of an instruction, the JVM sets the PC to next instruction. Method area is shared among all the threads of a process. Hence if more than one thread is accessing any specific method or any instructions, synchronization is needed. Synchronization in JVM is achieved through Monitors.

Garbage-collected Heap

The Garbage-collected Heap is where the objects in Java programs are stored. Whenever we allocate an object using new operator, the heap comes into picture and memory is allocated from there. Unlike C++, Java does not have free operator to free any previously allocated memory. Java does this automatically using Garbage collection mechanism. Till Java 6.0, mark and sweep algorithm is used as garbage collection logic. Remember that the local object reference resides on Stack but the actual object resides in Heap only. Also, arrays in Java are objects, hence they also resides in Garbage-collected Heap.

Core Java Performance

1.   Solutions to Improve the Performance


Performance is a key non functional requirement in any enterprise application. The term performance, in this context, refers to the capability of the system to achieve good response time with minimum CPU and memory utilization.

Following are some of the tips to be followed in coding, for improving the performance. 
  • Create Objects only when it is absolutely necessary and destroy them as soon as they are not needed.
  • Avoid Recursive method calls wherever possible. 
  • Avoid expensive method calls in loop control statements. 
  • Break loops when the purpose is served. 
  • For combining logical outputs, logical operators should be used instead of Bitwise operators. 
  • In a logical expression, simpler expressions should be given first and expensive expressions should follow. 
  • Reduce the scope of synchronized block to minimum. 
  • StringBuilder should be used in place of multiple String concatenations using + operator. 
  • Avoid synchronized collections like Vector and HashTable and use their non synchronized counterparts, ArrayList and HashMap. 
  • For using an object in a Set or Map, hashCode() should be implemented properly so that it returns distinct values without doing expensive calculations. 
  • Set performs better than List when large number of reads is required from the Collection. 
  • Always set the initial size of the Collection if it is already known. 
  • Type casting is an expensive operation and its usage must be minimized. 
  • Iterator gives consistent performance across different collection implementations when retrieving all the items from a collection. 

A Java code written properly by keeping performance in mind can improve the performance of the system dramatically. 


Performance is a key non functional requirement in any enterprise application. The term performance, in this context, refers to two aspects:

The response time and the CPU utilization: CPU utilization is the time spent by the system in CPU to perform an operation. Response time is the time required by the system to given response for a request. When CPU utilization increases response time also increases. But in addition to CPU utilization there are other factors which can affect response time. It includes waiting for a resource, waiting for response from another system and waiting for getting a lock. 
Memory utilization: Memory consumed by the system while performing an operation is memory utilization. High memory utilization increases the memory required for the deployment environment. It can also affect the response time of the system. Any application developer should try to minimize these. There are many factors which contribute to the performance of the system. Good architecture, efficient code, use of proper resources and good deployment infrastructure are some of the important factors which can give good performance for an application.

1.1. Basic Principles

  • Always keep performance in mind while doing coding. Let me make it work first. I will optimize it later is not a good approach. 
  • The program spends 90% of its time in 10% of the code”. So give importance to this 10%. Optimize the code which will be executed most of the time. Give importance to the code inside the loops. 
  • Reuse whatever available rather than reinventing the wheel. If proven components are available, use them. Those components will have less bugs and they will be optimized for performance. 

1.2. Object Creation

  • I will create as many objects as I wish. Garbage collector will remove them after I discard them. Correct, but garbage collection is an expensive operation 
  • Avoid the creation of unnecessary objects 
  • Explicitly set the member variables in an object to null, if the object is long living and the member variable is not needed. 
  • Explicitly set the local variables to null if it is not needed and the method is long lived. 
  • Cache the reused objects when possible. This can avoid overhead of creating objects and garbage collection. Negative impact is that caching will increase the memory usage. So whether to use caching or not is a tradeoff between memory and CPU utilization. 

1.3. Method Calls


The cost associated with method calls include transfer of control to the method, parameter passing, return value passing and establishment of method’s stack frame. But this doesn’t mean that it is better to write everything in a single method. Overhead of a method call is negligibly small compared to other operations we do in the method.

Technology Competence and Consulting

However, calling the same method repeatedly instead of caching the value should be avoided.

Example


a) if(employee.getAge() > 18 && employee.getAge() < 30) {
            validAge = employee.getAge();
    }

b) int age = employee.getAge();
    if(age>18&& age<30){
           validAge = age;
   }


b will perform better than a because three method calls are reduced to one in b.

More importantly, nested calls and recursive calls can create big stack build up, which can have a performance impact. Instead of having nested calls, where Method 1 calls Method 2 and Method 2 calls Method 3 and Method 3 calls Method 4, let Method 1 call Method 2, Method 3 and Method 4. This is easy to read and it will create smaller stack build up.
Performance impact due to recursive call is even worse. A method will be removed from the stack only when it is exited. When a method is called recursively all the method instances will exit only after the recursion stops, which can create huge stack build up and there is a possible chance of stack overflow error. So the recursive calls should be used only when it is absolutely necessary and the number of recursion is finite.
Overhead of recursive method calls can be demonstrated using the Code Sample 1. (Scroll down to view the example) 

1.4. Loop Optimization


Optimization of code inside loop is very critical because it will be called multiple times in a single execution.

1. Avoid method calls in loop control statement

Example

for(int i = 0; i < list.size(); i++)

can be replaced with

int size = list.size();
for(int i = 0; i < size; i++)

Note: with new versions of JVM, overhead with method calls is reduced a lot. So a
simple list.size() may not add much overhead. But expensive method calls need to be
avoided in the loop control statements.

2. Break the loops when purpose is served

Example

Employee employee = null;
for(int i = list.size() -1; i > -1; i--) {
    employee = (Employee)list.get(i)
          if(employee.getId().equals(givenId)) {
             requiredEmployee = employee;
             break;

        }

}

1.5. Bulk array operations


There are special methods for performing bulk operations on arrays. They are usually much faster than equivalent for loops, in part because they need to perform only a single bounds check.

static void java.lang.System.arrayCopy(src, si, dst, di, n) copies elements from array segment src[si..si+n-1] to array segment dst[di..di+n-1].

static bool java.util.Arrays.equals(arr1, arr2) returns true if the arrays arr1 and arr2 have the same length and their elements are pairwise equal. There are overloads of this method for arguments of type boolean[], byte[], char[], double[], float[], int[], long[], Object[] and short[].

static void java.util.Arrays.fill(arr, x) sets all elements of array arr to x. This method has the same overloads as Arrays.equals.

static void java.util.Arrays.fill(arr, i, j, x) sets elements arr[i..j-1] to x. This method has the same overloads as Arrays.equals.

static int java.util.Arrays.hashcode(arr) returns a hashcode for the array computed from the hashcodes of its elements. This method has the same overloads as Arrays.equals

1.6. Logical Operators


Boolean expressions should be combined using Logical operator instead of bitwise operators. ie Use && instead of &, and Use || instead of |. If the first expression confirms the result, other expressions will not be evaluated in case of logical operators. If the first expression is false in a logical AND, second expression will not be evaluated. Similarly, if the first expression is true in a logical OR, second expression will not be evaluated. In both the cases second expression is short circuited. So these operators are also called short circuit logical operators.

In a logical expression simple expressions should be given first and expensive expressions should follow. With this, there is a chance to get expensive expression short circuited which can save time.


Example
a) if(shouldValidate && isDataValid(data))
isDataValid will be called only if shouldValidate is true

b) if(shouldValidate & isDataValid(data))
isDataValid will be called even if shouldValidate is false. But irrespective of the result of
isDataValid expression will evaluate to false.

c)if(isDataValid(data) && shouldValidate)
Expensive isDataValid is provided as the first expression. It will be evaluated even if  shouldValidate is false

All the above codes will give the same result but a will have a better performance.

1.7. Static and Final


           
Constants have to be declared as static and final. Reference of static final constants will be replaced by its actual value during compilations. A word of caution here. If the value of a static final constant is modified in the code, it is required to compile the classes which use those constants to get the new value in it.

Methods which does not use instance variables can be declared static. Static methods are faster to execute. Code Sample 2 (Scroll down to view the sample code) shows that overhead of static method invocation is only 75% of that of non static method invocation.

Large objects which are put as static variables should be set to null when they are no longer required. Otherwise, they will never be garbage collected.

1.8. Exceptions

 The creation new Exception(...) of an exception object builds a stack trace, which is costly in time and space, and especially so in deeply recursive method calls. The creation of an object of class Exception or a subclass of Exception may be between 30 and 100 times slower than creation of an ordinary object. On the other hand, using a try-catch block or throwing an exception is fast.
 You can prevent the generation of this stack trace by overriding method fillInStackTrace in subclasses of Exception, as shown below. This makes creation exception instances roughly 10 times faster.

class MyException extends Exception {
public Throwable fillInStackTrace() {
return this;
}
}
            Thus you should create an exception object only if you actually intend to throw it. Also, do not use exceptions to implement control flow (end of data, termination of loops); use exceptions only to signal errors and exceptional circumstances (file not found, illegal input format, and so on). If your program does need to throw exceptions very frequently, reuse a single pre-created exception object.

1.9. Synchronized


The key word synchronized is used when we need to ensure thread safety. Use it only when it is absolutely necessary. And deciding on how to use it is as important as deciding on whether to use it or not.

Reduce the scope of the block to the minimum. Larger the block, longer the will be the wait for the other thread to get the lock.

Example
a) synchronized(lock) {
//local manipulations
//update shared data
}


b) //local manipulations
synchronized(lock) {
//update shared data
}

b will perform better because local manipulations are done outside the synchronized
block.

Do not use the same lock for multiple blocks unless you really want only one of those blocks to execute at a time. If you use the same lock for two blocks, when one thread is executing block 1, another thread, which want to execute block 2, has to wait.

Synchronized methods are locked on the same object (this).
Synchronized static methods are locked on the class object.

1.10.    I/O Operations


Disk reads are much slower than memory reads. So accessing the disk should be minimized. Caching of data should be considered instead of reading it multiple times using I/O operation.
       Reading and writing data in small chunks can be very slow. Use BufferedInputStream and BufferedOutputStream to batch the read and write requests. Buffered streams will buffer the data in the memory instead of accessing the disc each time. Size of the buffer can be controlled and it should be correctly chosen based on the use.

1.11.    Serialization


Serialization is a very costly operation. Its use should be minimized. Use ‘transient’ key word for variables that need not be read from/written into streams. The member variables which are declared transient will not be serialized. This will reduce the effort of serialization and de-serialization, and it will reduce the size of the data transferred trough the wire when the object is passed as a parameter to a remote call.

1.12.    String Concatenation


Strings are immutable. This means, value of a String cannot be changed. When we modify a String, a new String will be created with the new value. So each time another String is appended to it using + operator, a new String object will be created. This will prove costly when it is used inside loops.
Whenever a String need to be appended with other Strings multiple times, StringBuffer should be used. StringBuffer maintains a character array and the same array is updated each time another string is appended to it. String object will be created only when toString() method is called on it.
Code Sample 3 shows that there is huge performance difference between StringBuffer approach and + operator approach. Overhead is mainly attributed to the garbage collection of the old String objects. With StringBuffer approach there is no garbage collection overhead because a single object is getting updated in each execution.
With Java 5 and upwards, StringBuilder should be used instead of StringBuffer, if there is no thread safety issue. StringBuffer is thread safe while StringBulder is not. So StringBuilder has lesser overhead.

Note:
Consider the following code

String newString = someString + someString1 + someString2 + someString3;

This code is absolutely fine since only one instance of newString is being created here. Multiple + operators in a single statement will not deteriorate performance.

1.13.    Logging


Printing to console is a very heavy operation. So never use System.out.println in you code. Use loggers instead. Loggers give the flexibility to enable and disable logging any time we want. Even when we use a logger there are a few things to take care.
All the conversions and concatenations, which are used to arrive at the String to be logged, are executed even when the logging is disabled. So before doing such expensive operations, it is better to check whether the logging is enabled for that level. The same check needs to be done before executing a loop for logging.

Example

a) logger.fine(employeeVo.toString()); //AVOID. toString() is always executed

if(logger.isLoggable(Level.FINE)) { //PREFERABLE
logger.fine(employeeVo.toString());
}

b) for(int i = 0; i < size; i++) { //AVOID. Loop is always executed
logger.fine(names[i]);
}

if(logger.isLoggable(Level.FINE)) { //PREFERABLE
for(int i = 0; i < size; i++) {
logger.fine(names[i]);
}
}

1.14.    Sorting and searching


Never use selection sort, bubblesort or insertion sort, except on very short arrays or lists. Use heapsort (for arrays) or mergesort (for doubly linked lists) or quicksort (for arrays; but you must make a good choice of pivot element).

 Even better, use the built-in sorting routines, which are guaranteed to be fast: O(n log(n)) time for n elements, and sometimes faster if the data are nearly sorted already:
 For arrays, use java.util.Arrays.sort, which is an improved quicksort; it uses no additional memory, but is not stable (does not preserve the order of equal elements). There are overloaded versions for all primitive types and for objects.
For ArrayList<T> and LinkedList<T>, implementing interface java.util.List<T>, use java.util.Collections.sort, which is stable (preserves the order of equal elements) and smooth (near-linear time for nearly sorted lists) but uses additional memory.

 Avoid linear search in arrays and lists, except when you know that they are very short. If your program needs to look up something frequently, use one of these approaches:
Binary search on sorted data:
For arrays, use java.util.Arrays.binarySearch. The array must be sorted, as if by java.util.Arrays.sort. There are overloaded versions for all primitive types and for objects.
For ArrayList<T>, use java.util.Collections.binarySearch. The array list must be sorted, as if by java.util.Collections.sort. If you need also to insert or remove elements from the set or map, use one of the approaches below instead.
Hashing:
Use HashSet<T> or HashMap<K,V> from package java.util if your key objects have a good hash function hashCode. This is the case for String and the wrapper classes Integer, Double, . . . , for the primitive types.
Binary search trees:
Use TreeSet<T> or TreeMap<K,V> from package java.util if your key objects have a good comparison function compareTo. This is the case for String and the wrapper classes Integer, Double . . . for the primitive types.

1.15.    Collection Performance


In most of the Java applications, collections are extensively used and their performance is very critical.

Synchronized Collection

Avoid synchronized collections if thread safety is not an issue. Vector and Hashtable are synchronized collections while ArrayList and HashMap are their non synchronized counterparts. Synchronized collections will have overhead of synchronizing while non synchronized collections will not have that.

Implementation of hashcode()

               Implementation of hashCode() has an important role in performance of Hashtable, HashMap and HashSet. To know the importance of hash code, we need to understand how items are arranged in a hashed collection and how the search is done in the collection. Objects are arranged in the order of their hash code. Both equals() and hashCode() are used while searching for an Object. Objects which match the hash code will be taken first. After that, equals() will be called on each of them to find the exact match.
 Performance of the hashed collection will depend on the number of objects which match the hash code. Smaller the number of matches better will be the performance. So hash code should be preferably unique. But one should also consider that cost of finding the hash code should be minimum. There is no need to make the hash code finding expensive, just to make it unique.
For example, consider the case of an Employee object which stores id, name, age, and ten other attributes. Since ID is unique it is enough to use the id to calculate the hash code. If id is not present in the object, you can consider using only the name to calculate the hash code, instead of using all the twelve attributes. Even though name is not unique, it mostly gives distinct values, which is enough to give good performance while searching.

Array List or HashSet

              ArrayList stores items in the sequence in which it is added to the list. HashSet stores them based on the hash code. So finding of an item is faster in HashSet. But adding a new item is slower because HashSet needs to arrange the items based on hash code. Consider the use of HashSet instead of ArrayList when all the following three conditions satisfy.

· There is no need to store the same entry more than once.
· Order of the added object is not important.
· Searching of an element is a frequent operation.

Code Sample 4 shows the benefit of using Set in place of List. It also shows how the performance can get deteriorated with a poor hashCode() implementation. Search on a Set with 10000 item took only one thirtieth of the time compared to the search on a List with same size. But, with a poor hashCode() implementation, time taken by the Set became 4 times the time taken by the List.

Initial Size

           Generally we say that collections don’t have a fixed size. But all the collections internally use arrays of fixed size to store the objects. These arrays will have a small initial size when the size is not explicitly specified.
When the array is full it has to be resized. But as the size of the array cannot be changed, a bigger array is newly created and all the elements in the old array is copied to the new array. This is definitely an overhead. So if we know the size of the collection initially, it is better to initialize the collection with the known size. See

Code Sample 5. Addition to the list without initial size took 60% more time compared to the list with initial
size.

Type Casting Overhead

            A main overhead of using collection is the type casting required when we retrieve items from the collection. Type casting is an expensive operation in Java as it is done in runtime. So use of casting should be minimized. The Code Sample 6 shows that assigning the casted value to a variable and using it, is better than doing casting twice. Even with two casting in the loop, 25% extra time is taken compared to one casting.

           Another point to be noted is about generics. Even though generics eliminate the need of casting in the code, it doesn’t avoid the casting during runtime. The byte code generated after compilation will be exactly the same whether we use generics or type casting. So the performance rule of type casting applies to generic gets as well.

            If you need to deal with a collection in a highly performance critical code, creating a specialized collection can be considered. This specialized collection class will be dealing with the specific class type rather than java.lang.Object. So there is no need for a casting when you retrieve an item from the specialized collection. You need to implement the just enough functionality you expect from the collection, instead of implementing the all the methods of Collection or List. The Code Sample 7 shows that performance can be improved considerably with specialized collection.
                                                                                                                                                               Retrieval Mechanism

            There are different mechanisms to retrieve all the items from a List and these mechanisms have their own performance implications.

1. Retrieve using get(int) method – We can increment the index and retrieve the items from the List using get method. This is faster in the case of Lists which maintain the items as an array. Eg: ArrayList and Vector. But in the case of lists like LinkedList reaching at an index is very difficult. so using get can drastically reduce performance.
                                                                                                                                                               2. iterator – Iterator can be used to retrieve items from any Collection. In case of ArrayList and Vector, iterator gives slightly lesser performance when compared with get. But in case of LinkedList iterator can provide you good performance because items are linked with each other and getting the next item when compared with current position is easier than getting an item using an index.

3. Advanced for loop – With Java 5 and upwards, advanced for loop can be used to iterate on a collection. Performance of advanced for loop is same as that of iterator because advanced for loop uses iterator internally. It is recommended to use iterator (or advanced for loop in case of Java 5 and upwards) to retrieve all the items from the list due to following reasons.

1. It provides better abstraction (can be used on any collection, not just List)
2. It provides consistent performance on all collection implementations.
3. It is less prone to programming errors. (ArrayIndexOutOfBound exception, missing first or last item etc.)

                 But for sheer performance, get(int) can be used if we are sure that implementations is an ArrayList or Vector. Code Sample 8 show the performance of get, iterator and advanced for loop on ArrayList and Linked List


Code Sample 1   - Recursion

import java.util.*;
public class Recursion {
private static int count = 0;
public static void main(String [] args) {
long time = System.currentTimeMillis();
if(args[0].equals("yes")) {
    performWithRecursion();
    } else {
        boolean shouldContinue = true;
        while(shouldContinue) {
        shouldContinue = performWithOutRecursion();
        }
    }
System.out.println("Time "+(System.currentTimeMillis() -time));
    }

public static void performWithRecursion() {
Date date = new Date();
ArrayList list = new ArrayList();
for(int i = 0; i < 10000; i++) {
list.add(date);
}

if(count++ < 100) {
performWithRecursion();
}
}

public static boolean performWithOutRecursion() {
Date date = new Date();
ArrayList list = new ArrayList();
for(int i = 0; i < 10000; i++) {
list.add(date);
}
return count++ < 100;
}
}

Time with recursion : 200ms
Time without recursion : 90ms

Code Sample 2 – Static Methods

public class StaticTest {
public static void main(String [] args) {
long time = System.currentTimeMillis();
StaticTest test = new StaticTest();
if(args[0].equals("yes")) {
for(int i = 0; i < 100000000; i++) {
test.staticMethod();
}
} else {
for(int i = 0; i < 100000000; i++) {
test.nonStaticMethod();
}
}
System.out.println("Time "+(System.currentTimeMillis() -time));
}
private static void staticMethod() {
}
private void nonStaticMethod() {
}
}

Time with static method : 300ms
Time with non static method : 400ms


Code Sample 3 – String Concatenation

public class StringConcat {
public static void main(String [] args) {
long time = System.currentTimeMillis();
StringBuffer buffer = new StringBuffer();
String s = "";
if(args[0].equals("no")) {
for(int i = 0; i < 100000; i++) {
buffer.append(i);
if(i%1000 == 0) {
buffer.delete(0, buffer.length());
}
}
s = buffer.toString();
} else {
for(int i = 0; i < 100000; i++) {
s+=i;
if(i%1000 == 0) {
s = "";
}
}
}
System.out.println("Time "+(System.currentTimeMillis() -time));
}
}

Time with + operator: 3750ms
Time with StringBuffer: 30ms

Code Sample 4 – Set or List

import java.util.*;
public class SetOrList {
public static void main(String [] args) {
long time = System.currentTimeMillis();
if(args[0].equals("set")) {
Set set = new HashSet();
for(int i = 0; i < 10000; i++) {
set.add(new Employee("id"+i, "name"+(i%1001), i%100));
}
for(int i = 0; i < 10000; i++) {
set.contains(new Employee("id"+i,"name"+(i%1001),i%100));
}
} else {
List list = new ArrayList();
for(int i = 0; i < 10000; i++) {
list.add(new Employee("id"+i, "name"+(i%1001), i%100));
}
for(int i = 0; i < 10000; i++) {
list.contains(new Employee("id"+i,"name"+(i%1001),i%100));
}

}
System.out.println("Time taken "+(System.currentTimeMillis()-time));
}
}

public class Employee {
private String employeeName;
private String id;
private int age;
public Employee (String id, String employeeName, int age) {
this.id = id;
this.employeeName = employeeName;
this.age= age;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public void setId(String id) {
this.id = id;
}
public void setAge(int age) {
this.age= age;
}
public String getEmployeeName() {
return employeeName;
}
public String getId() {
return id;
}
public int getAge() {
return age;
}
public boolean equals(Object object) {

if(object != null &&
object instanceof Employee) {
Employee emp = (Employee) object;
return employeeName.equals(emp.employeeName) &&
id.equals(emp.id) &&
age == emp.age;

}
return false;
}
public int hashCode() {
return id.hashCode(); //OPTION 1
//return -1; //OPTION 2
}
}
Time with List : 4750 ms


Time with Set and OPTION 2 commented : 150 ms
Time with Set and OPTION 1 commented : 18000 ms

Code Sample 5 – Initial Capacity

import java.util.*;
public class InitialCapacity {
public static void main(String [] args) {
long time = System.currentTimeMillis();
for(int j = 0; j < 100000; j++) {
if(args[0].equals("yes")) {
List list = new ArrayList(100);
for(int i = 0;i < 100; i++) {

list.add("test");
}
} else {
List list = new ArrayList();
for(int i = 0;i < 100; i++) {

list.add("test");
}
}
}
System.out.println("Time "+(System.currentTimeMillis()-time));
}
}

Time with initial Capacity : 500 ms
Time without initial Capacity : 800 ms


Code Sample 6 – Casting Overhead


public class CastOverhead {
public CastOverhead(boolean isCastOverhead) {
if(isCastOverhead) {
Object employee = new Employee("test", "test", 23);
for(int i = 0; i < 100000000; i++) {
((Employee)employee).getEmployeeName();
((Employee)employee).getId();
}

} else {
Object object = new Employee("test", "test", 23);
for(int i = 0; i < 100000000; i++) {
Employee employee2 = (Employee)object;
employee2.getEmployeeName();
employee2.getId();
}
}
}
public static void main(String [] args) {
long time = System.currentTimeMillis();
new CastOverhead(args[0].equals("yes"));
System.out.println("Time "+(System.currentTimeMillis()-time));


}
}

Time with Cast overhead : 600 ms
Time without Cast overhead : 475 ms

Code Sample 7 – Specialized Collection 


public class EmployeeCollection {
private Employee[] activeEmployeeArray;
private int activeEmployeeArrayLength;
public EmployeeCollection() {
activeEmployeeArrayLength = 0;
activeEmployeeArray = new Employee[10];
}
public void add(Employee employee) {
ensureCapacity(activeEmployeeArrayLength + 1);
activeEmployeeArray[activeEmployeeArrayLength++] = employee;
}
public void ensureCapacity(int size) {
if (size > activeEmployeeArray.length) {
int newSize = activeEmployeeArray.length * 2;
if(newSize < size) {
newSize = size;
}
Employee oldData[] = activeEmployeeArray;
activeEmployeeArray = new Employee[newSize];
System.arraycopy(oldData, 0, activeEmployeeArray, 0, activeEmployeeArrayLength);
}
}
public int size() {
return activeEmployeeArrayLength;
}
public Employee get(int i) {
return activeEmployeeArray[i];
}
}


import java.util.*;
public class SpecializedCollection {
public SpecializedCollection(boolean isSpecializedCollection) {
long time = System.currentTimeMillis();
if(isSpecializedCollection) {
EmployeeCollection list = new EmployeeCollection();
for(int i = 0; i < 10000; i++) {
list.add(new Employee("id"+i, "name"+(i%1001), i%100));
}
time = System.currentTimeMillis();
for(int j = 0; j < 10000; j++) {
for(int i = 0; i < 10000; i++) {
Employee emp = list.get(i);
}
}
} else {
List list = new ArrayList();
for(int i = 0; i < 10000; i++) {
list.add(new Employee("id"+i, "name"+(i%1001), i%100));
}
time = System.currentTimeMillis();
for(int j = 0; j < 10000; j++) {

for(int i = 0; i < 10000; i++) {
Employee emp = (Employee)list.get(i);
}
}
}
System.out.println("Time taken "+(System.currentTimeMillis() -time));
}
public static void main(String [] args) {
new SpecializedCollection(args[0].equals("yes"));
}
}

Time with Specialized collection: 280 ms
Time without Specialized collection: 1700 ms

Code Sample 8 – Retrival From List

import java.util.*;
public class IteratorOrGet {
public static void main(String [] args) {
List list = null;
if(args[0].equals("ArrayList")) {
list = new ArrayList();
} else (args[0].equals("LinkedList")) {{
list = new LinkedList();
}
for(int i = 0; i < 20000; i++) {
list.add(new Integer(i));
}
long time = System.currentTimeMillis();
if(args[1].equals("get")) {
for(int j= 0; j < 100;j++) {
for(int i = list.size() -1; i > -1; i--) {
Object o = list.get(i);
}
}
} else if(args[1].equals("iterator")) {


for(int j= 0; j < 100;j++) {
Iterator iterator = list.iterator();
while(iterator.hasNext()) {


Object o = iterator.next();
}
}
} else if(args[1].equals("advancedForLoop")) {

for(int j= 0; j < 100;j++) {
for (Object o : list) {
}

}
}
System.out.println("Time taken "+(System.currentTimeMillis() -time));
}
}
ArrayList
Time with get  : 30 ms
Time with Iterator : 70 ms
Time with Advanced For Loop : 70 ms

LinkedList
Time with get : 95795 ms
Time with Iterator  : 50 ms
Time with Advanced For Loop : 50 ms 

1.16.    OutOfMemoryError


One common issue that many developers have to address is that of applications that terminate with java.lang.OutOfMemoryError. That error is thrown when there is insufficient space to allocate an object. That is, garbage collection cannot make any further space available to accommodate a new object, and the heap cannot be further expanded. An OutOfMemoryError does not necessarily imply a memory leak. The issue might simply be a configuration issue, for example if the specified heap size (or the default size if not specified) is insufficient for the application

The first step in diagnosing an OutOfMemoryError is to examine the full error message. In the exception message, further information is supplied after “java.lang.OutOfMemoryError”. Here are some common examples of what that additional information may be, what it may mean, and what to do about it:

Java heap space
This indicates that an object could not be allocated in the heap. The issue may be just a configuration problem. You could get this error, for example, if the maximum heap size specified by the –Xmx command line option (or selected by default) is insufficient for the application. It could also be an indication that objects that are no longer needed cannot be garbage collected because the application is unintentionally holding references to them. The HAT tool can be used to view all reachable objects and understand which references are keeping each one alive. One other potential source of this error could be the excessive use of finalizers by the application such that the thread to invoke the finalizers cannot keep up with the rate of addition of finalizers to the queue. The jconsole management tool can be used to monitor the number of objects that are pending finalization.

PermGen space
This indicates that the permanent generation is full. As described earlier, that is the area of the heap where the JVM stores its metadata. If an application loads a large number of classes, then the permanent generation may need to be increased. You can do so by specifying the command line option –XX:MaxPermSize=n, where n specifies the size. Some of the default values for Sun JVMs are listed below.
 
JDK 1.3.1_06
Initial Size
Maximum Size
Client JVM
1MB
32MB
Server JVM
1MB
64MB

JDK 1.4.1_01
Initial Size
Maximum Size
Client JVM
4MB
64MB
Server JVM
4MB
64MB

JDK 1.4.2
Initial Size
Maximum Size
Client JVM
4MB
64MB
Server JVM
16MB
64MB

JDK 1.5.0
Initial Size
Maximum Size
Client JVM
8MB
64MB
Server JVM
16MB
64MB


Requested array size exceeds VM limit
This indicates that the application attempted to allocate an array that is larger than the heap size. For example, if an application tries to allocate an array of 512MB but the maximum heap size is 256MB, then this error will be thrown. In most cases the problem is likely to be either that the heap size is too small or that a bug results in the application attempting to create an array whose size is calculated to be incorrectly huge.

Some of the tools described in the below Section can be utilized to diagnose OutOfMemoryError problems. A few of the most useful tools for this task are the Heap Analysis Tool (HAT), the jconsole management tool, and the jmap tool with the –histo option.


• The heap size setting (-Xms and -Xmx) is too small.

• -Xmx setting is too large in 32-bit JVM. The 32-bit JVM has 4GB address space, which includes not only Java heap but also stack, JVM libraries and native heap.

• The permanent generation (–XX:PermSize and -XX:MaxPermSize) setting is too small to accommodate class, method objects and interned strings. This problem could happen in large scale Java EE and web services applications.

• The physical memory and swap space setting on the operating system are too small or other processes in the system consume all memory resources.

• The application or 3rd party libraries create huge amounts of temporary objects and consume lots of heap memory. These live objects can not be collected until some processing logics are completed. This could happen particularly in xml processing, report generating, image processing, large file processing, etc. Redesigning the software or algorithm to use memory more efficiently is needed to solve this kind of problem.

• The application process enters an unlimited cycle (dead cycle) eating up CPU cycles and creating objects very fast, causing GC thread could not kick in and collect objects timely.

• Memory mapping a huge-size file in 32-bit JVM. The 32-bit JVM address space is 4GB, mapping too big file will cause problems.

• A lot of objects pending on finalization. There is no guarantee when a finalizer will be run or that it will be run at all. An object that has a finalizer will not be garbage collected until its finalizer is run. This can cause lots of objects cannot be collected timely. The finalize method is used for making sure to release external resources in the end

For “unintentional object retention” memory leak, the reasons could be:

• Forgetting to release resources explicitly in the codes, such as connections, JDBC statements, etc. The method name is not always “close()” though. For example, forgetting to call end() method of java.util.zip.Defaltor after the compressor is no long used will cause the native heap space cannot be released timely. The finalize() method of java.util.zip.Defaltor also calls end() method automatically, but as above stated, you should not reply on finalizers to clean up resources timely.

• An exception throws before releasing resources. As a good practice, the codes releasing resources should be in “finally{}” clause.

• Some applications or Java libraries use hash maps, arrays or other similar Java collection objects to cache or track objects but the codes forgets to remove them from the hash map when those objects are not needed any more. This problem often occurs on some complicated server-side Java applications or some heavy-weight Java GUI applications.

• Permanent generation leak. In most Java EE environments, each web module or EJB module has a separate classloader. Incorrect use of class references will cause the application classes and its classloaders cannot be collected even after the application is undeployed. Any reference from outside the application to an object in the application of which the class is loaded by the application's classloader will cause a classloader leak.

• Memory leaks in native codes. It is the leak in native heap, probably because of the bug of JNI codes or JVM. In this case you will not see leak problems in Java heap. Diagnosing this problem varies on different operating systems. On Solaris, prstat, pmap, dbx, mdb can help detect and diagnose the native heap memory leak.


Two JVM options are often used to tune JVM heap size: -Xmx for maximum heap size, and -Xms for initial heap size. Here are some common mistakes I have seen when using them:
  • Missing m, M, g or G at the end (they are case insensitive). For example,
java -Xmx128 MyApp

java.lang.OutOfMemoryError: Java heap space
 
The correct command should be: java -Xmx128m MyApp. To be precise, -Xmx128 is a valid setting for very small apps, like HelloWorld. But in real life, I guess you really mean -Xmx128m
  • Extra space in JVM options, or incorrectly use =. For example,
java -Xmx 128m MyApp

Invalid maximum heap size: -Xmx

Could not create the Java virtual machine.



java -Xmx=512m HelloWorld

Invalid maximum heap size: -Xmx=512m

Could not create the Java virtual machine.
 
The correct command should be java -Xmx128m MyApp, with no whitespace nor =. -X options are different than -Dkey=value system properties, where = is used.
  • Only setting -Xms JVM option and its value is greater than the default maximum heap size, which is 64m. The default minimum heap size seems to be 0. For example,
java -Xms128m MyApp

Error occurred during initialization of VM

Incompatible initial and maximum heap sizes specified
 
The correct command should be java -Xms128m -Xmx128m MyApp. It's a good idea to set the minimum and maximum heap size to the same value. In any case, don't let the minimum heap size exceed the maximum heap size.
  • Heap size is larger than your computer's physical memory. For example,
java -Xmx2g MyApp

Error occurred during initialization of VM

Could not reserve enough space for object heap

Could not create the Java virtual machine.
The fix is to make it lower than the physical memory: java -Xmx1g MyApp
  • Incorrectly use mb as the unit, where m or M should be used instead.
java -Xms256mb -Xmx256mb MyApp

Invalid initial heap size: -Xms256mb

Could not create the Java virtual machine.
  • The heap size is larger than JVM thinks you would ever need. For example,
java -Xmx256g MyApp

Invalid maximum heap size: -Xmx256g

The specified size exceeds the maximum representable size.

Could not create the Java virtual machine.
 
The fix is to lower it to a reasonable value: java -Xmx256m MyApp
  • The value is not expressed in whole number. For example,
java -Xmx0.9g MyApp

Invalid maximum heap size: -Xmx0.9g

Could not create the Java virtual machine.
 
The correct command should be java -Xmx928m MyApp