Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Wednesday, January 28, 2009

Multithreading - Downstream Impacts

Multi threaded model will in most of the cases give better performance for batch applications. I would look at the below mentioned points along with the reengineering of the application code.
  • Processing Power – There should be enough CPU power available in the machine.
  • Memory – Since all threads will be working in parallel, the amount of memory used also will be considerably high. This can be however be reduced by not placing too many objects in JVM. However, the amount of memory required will be proportional to the number of threads in the application.
  • Network Load – If the application is having network interactions like Database queries, FTP etc, the network load also will be high. In some cases, it would be solved by adding GBit connections between servers communicating. In most of the cases, the normal NIC’s itself can process the load.
  • Disk Speed – If the application has lot of File processing, the disk accesses also need to be tuned. It would be better to read the files from SAN rather than NAS as the disk response time is better on SAN (my experience).
  • Database Setup – If there is lot of database interactions, the database also should be made aware of such a change in the application. The load on the database will increase as there will be multiple threads that will try to fetch data from database. Most probably, it will end up increasing the database parameters to accept more loads.
  • GC processing – The GC tuning should be performed. Since many threads are working in parallel, the amount of garbage created also will be high. An effective tune up of GC is required, without which, application will end up in OutofMemory Error. You can consider Parallel GC but ensure that the number of GC threads is mentioned.
  • Synchronization – Objects that are created in JVM scope should be accessed with proper synchronization. If this is not worked out properly, it can cause dreaded issues like data corruption, deadlocks etc…

Multithreading Multiprocessor Relation

A batch application is made scalable by ensuring that the executable can use the complete power provided by the machine. The batch application should be designed as multithreaded model if it’s possible to break the work into multiple smaller units of work. In this way, each thread can work on its own piece of work and complete the work. For e.g. In a single threaded model, the batch processes takes 10 hours to process 2000 customer records. If the same code is written in multi threaded model using 10 threads, the job can be split into 10 units with each unit having to process 200 customers. The same work can be completed in 1 hour. Caveat being the machine has the necessary processing power (CPU)

Any java process executes in a thread of execution. The thread can perform multiple activities like performing the task, waiting on IO, waiting on socket, waiting for lock release etc. While the thread is waiting on something, CPU is intelligent enough to remove the thread from its cycle and take up another thread which can perform the work. Any point in time, a CPU core can execute only one thread. So if the machine has 4 cores of CPU, an ideal count would be to provide 3 threads/core for the application to use. The number of threads per core is dependent on the application, primary driving factor being what is done in each thread. If there considerable wait that will happen in the thread of execution (like File IO, database read, Socket read) , the number of threads per CPU can be increased and if the thread is going to perform operations within the process area without any wait, the number of threads per CPU should be reduced. This is because the machine always pushes out the threads that are waiting and takes in thread that is ready for execution.

Impact on number of threads

More threads/core for application that has less amount of wait.
Let’s take an example where the machine has 2 CPU’s and application is configured to use 10 threads. Since there is not much wait time involved, the CPU will force the executing thread out of its cycle to give fair chance for the remaining 9 threads to execute. The thread that got pushed out will come back to execution after certain CPU cycles. At this time, it needs to rebuild till the point where it was pushed out. If there were only 1 thread of execution per CPU, this type of activity won’t happen and the single thread /CPU can complete the operation without heavy context switching. In such a scenario, it will be detrimental for the application. Such a case will be evident if the batch completes in lesser time when the number of threads for the application is reduced.
Less threads/core for application that has considerable amount of wait.
Let’s take an example where the machine has 8 CPU’s and application is configured to use 8 threads. Each CPU will execute a thread of execution and when any one of the thread goes into WAIT state, the CPU lies idle. Such a case will be evident if the batch completes in lesser time when the number of threads for the application is increased. At any point in time, the CPU usage will not be near 50% or 60%.

As mentioned in the above description, the number of threads per CPU should be decided based on the application characteristics.

Friday, December 5, 2008

JDK Logging

Log4j is widely accepted as a logging component. There is yet another one, the logging component inbuilt in java. This article will discuss about the logging provided by JDK.

Ideal scenario, the entire configuration can be done through the logging.properties file. The logging.properties file should be present in the classpath of the application. In case you want to provide a different properties file, the same can be set using the system property. The command is as shown below

java –Djava.util.logging.config.file=/home/users/mypath/mylogging.properties

The logging.properties file sample is present in the jre/lib folder. This file can be edited to get the necessary logging. The structure of the logging properties file is shown below


#Defines the handlers which can be used by the logger. It can be comma separated. For
# each handler, definition should be provided in the properties file
handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
#Default level of logging in case specific logging level as shown in the last line is not
# mentioned.
.level= INFO
#Details about the filehandler.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

#custom logging level
com.xyz.foo.level = SEVERE

By default the logging happens at the package level of the class when you are using the property file for configuring the logger.

The restrictions here are that we can specify only one log file per logging properties file. So in case you need the log to go to multiple files, may be based on the application, it’s not possible through configuration in the properties file. However, you can perform the above requirement by writing a specific logger class.


private void initialize(String name)
{
Handler fileHandler;
try {
fileHandler = new FileHandler(filePath, true);
fileHandler.setFormatter(new MyFormatter());
logger=Logger.getLogger(name);
logger.addHandler(fileHandler);
}
public static MyLogger getInstance(String someName)
{
//add the necessary synchronization blocks
mylogger = new MyLogger();
mylogger.initializer(someName);
return mylogger;
}
//this is sample method. Like this you need to provide implementation for
//all other methods
public void debug(String sourceClass, String sourceMethod, String msg)
{
logger.logp(Level.FINEST,sourceClass,sourceMethod,msg);
}
//in your application code, use it this way
MyLogger logger = MyLogger.getInstance(“namethatidentifiestheloglevel”);
logger.debug(“classname”,”methodname”,”msg”);

In the above code snippet, the log level is not mentioned. The log level can be mentioned in the properties file that is passed as the java.util.logging.config.file property. In this case, the value will be set as

namethatidentifiestheloglevel=SEVERE

There are various levels available, the important ones being SEVERE, INFO, FINE, FINEST, DEBUG etc … Please refer to the sun documentation site as the priority of the log level does matter in the content that gets logged.

Saturday, November 1, 2008

Class Loader Hierarchy

As per the delegation contract, a class should be attempted to be loaded by the parent class loader. If the parent class loader cannot load the class, the request should then be handed over to the child class loader. The process will continue till the class loader which originally received the request to load the class. Still if the class cannot be located in the classpath, a ClassNotFoundException is thrown. The request will not be transmitted to the child class loaders of the class loader which originally received the request to load the class.

Say we have 4 class loaders with names as shown below. ClassLoaderX, ClassLoaderY, ClassLoaderA, ClassLoaderB. The relations between them are shown below

When the JVM starts, all classes accessible from /x/data can be loaded by the ClassLoaderX. Then the control is transferred to ClassLoaderY, which can load the classes present under /y/data folder. The control is transferred to ClassLoaderA as well as to ClassLoaderB which can load the classes under /a/data and /b/data. The classes loaded by the parent class will not be loaded by the child class loader again as the child class loader will check if the classes are already loaded by any of its parent class loaders.

Now when the ClassLoaderB gets a request to load a class, it will delegate the request to its parent class loader i.e. ClassLoaderY. The ClassLoaderY will delegate the request to its parent classloader ClassLoaderX. Since ClassLoaderX does not have any parent class loader, it will try to load the class from its classpath i.e. /x/data. If the class is present in its classpath, it will load the class. If it cannot find the class in its classpath, the request is delegated to the child classloader i.e. ClassLoaderY. The ClassLoaderY will attempt to load the class from its classpath /y/data. If it finds the class, the class will be loaded by the ClassLoaderY. If it cannot find the class, the request is delegated to the ClassLoaderB. ClassLoaderB will attempt to load the class from its classpath. If it cannot find the class in its classpath, the request cannot be delegated to the child classloader of ClassLoaderB. Instead it will throw a ClassNotFoundException.

Consider a scenario where the following jar packaging is done. Class P is having Class Q as its super class. Class Q refers to Class R. P is packaged in p.jar and placed in /b/data folder. Q is packaged in q.jar file and placed under /x/data folder and R is packaged in r.jar and placed in /b/data folder. Can you guess what happens!

ClassLoaderB will try to load P and it will load the class after ClassLoaderY and X attempts to load it. Since P has Q as the super class, ClassLoaderB will attempt to load it. Q will be loaded by ClassLoaderX as Q is placed in the classpath of ClassLoaderX. Now Q refers to R and hence ClassLoaderX tries to load it. It will give ClassNotFoundException as r.jar is not present in classpath of ClassLoaderX. As per the policy, the loader should not delegate the request to child classloader and hence ClassLoaderB will never be asked to load R.

If a class is already loaded by the parent classloader, the child classloader will not attempt to load the class again. However some application servers have written custom classloaders which override these features. Another point to note is that the same class will be loaded by ClassLoaderA and ClassLoaderB if the class is placed in their classpath. This is because the classloader always checks its parent for loaded classes but not its children or siblings.

Java has got bootstrap classloader, extension classloader and application classloader by default. Bootstrap classloader can be mapped to ClassLoaderX, extension classloader can be mapped to ClassLoaderY and application classloader can be mapped to ClassLoaderB in the example above.

Few pointers

  1. Do not place the jars in the bootstrap classpath or the extension classpath just to make the application work. It will create issues which might surface later.
  2. Packaging the application is important because it impacts the class loading order too. All related classes should be packaged together or the proper documentation should be provided as to what order the jars should be loaded.
  3. Place common utility jars and common files in common classloaders path. However caution should be taken if they are supposed to be used in an independent manner. For e.g.: log4j.properties, if loaded by parent classloader, the properties file present in the child classloader path will never be considered and might give annoying results.

Avoding log4j logger statements in log files

We all have used log4j in multiple scenarios and it serves the purpose. There are cases when we don’t want the logger statements from few classes or few packages to clutter the log files. Some other cases, we want the logger statement to be printed in only one log file and not in all log files. These are 2 different cases and I will explain solution for both of the requirements.

Requirement 1: Don’t print the log statements in any of the configured log files. Consider a scenario where we have configured 4 -5 log files at different levels and for different purposes. If we don’t want the logger statement from the classes in a particular package or particular class to appear in any of these log files, we have to use the following syntax.

log4j.category.=OFF

e.g. log4j.category.com.test.welcome=OFF means that all the statements logged from the classes present in com.test.welcome package will not be logged in any of the configured log files.

Requirement 2: Don’t print the same log statements in all of the configured log files. It should be printed in the more specific log file only. Consider the scenario like this

log4j.category.com.pack1.pack2 = INFO, appender1

log4j.category.com.pack1 = INFO, appender2

The statements logged from the classes present in the package com.pack1 will be printed in the appender2 as well as appender1 log files as both of them satisfy the category. Now if we don’t want the logger statements from the pack2 not to print in appender1, then we can use the additivity clause.

# set additivity to false to ensure that the parent appenders do not log these statements
log4j.additivity.pack2 =false

The above line means that the logger statement from pack2 will be present only in appender1 log file and not in appender2 log file. This is because the logger file is configured for appender2 as well as appender1. That means the logger statement got printed only in the specific log file and not in its parent appenders.

Thursday, October 2, 2008

Java application seems to hang???

(JMAP JHAT & GCORE)

Intended Audience

Basic knowledge about memory settings for java processes and UNIX commands is required. This article knowledge can be used to debug memory issues related to applications deployed in application servers or standalone java processes.

Last week I was looking into a batch application which is designed for an uptime of 24X7X365. The application processes data very efficiently and fast when the application is started. After certain point of time, the application was not processing any data or rather it was becoming progressively slow. To fix the issue, I had to do some amount of research and since I did not find any directly available documentation, I decided to do it myself. Although the experience I put here is for batch application the same can be used for web application and any other type of applications that use JDK6 or above.

This article will explain few tactics that can be used to identify if the application is hanging or not responding due to memory issues or if there are some possible memory leaks. This article assumes that you are running the application in UNIX environment with SUN JVM. The syntax used might be slightly different for windows environment in case you want to tailor it for windows environment.

To give a gist of the application that I used, it processes and compares different versions of XML documents. The application processes the data in batches. During the initial hours of the application, the rate of completion was 12 batches/hour (ignore what a batch size is as this is used only for showing relative figures). After 3 hours, the rate of execution dropped to 3 batches / hour and after 5 hours, the rate dropped to 1 batch / hour. This showed that the application was having some problem, which could be memory leaks, locks, CPU contention, Network issues, and or database issues.

CPU Usage

The CPU usage during the first, third and fifth hour were 99.3%, 75% and 4% respectively. This was hinting that the application was not really processing the data as it progressed. So the next step was to find out what was happening. The possible hints are that the system is doing something else which doesn’t require so much of CPU like GC, IO Wait, Locks etc.

Thread Dump

The thread dump of the process was taken to figure out the state of each thread. The application was using a batch framework designed on multithreading. Hence the thread dump showed details for all of the 20 threads it was using.

The syntax to take the thread dump in UNIX is

kill -3

The output will be redirected to the standard output log configured for your process. Remember its not the log4j logs, it’s the standard output log. Most of the application servers name it (of course you can configure it) as SystemOut.log

The thread dump showed that all the 20 threads were in RUNNABLE state. This showed that the application threads are not in any deadlock situation and neither is it waiting for a monitor entry (like synchronized blocks). This also showed that the threads were not waiting on IO.

Memory Profiling

The next area to investigate was the memory. The process was started again with the following command line parameters to get the GC details printed.

“-Xloggc:/usr/berfty/gc_log.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"

We aimed at GC processes details as it will explain what are the events happening with respect to the memory. The GC log can give details

  1. How much objects are still referenced by the application.
  2. How much objects are removed from the memory.
  3. How many times Full GC happens.
  4. Time taken for the GC process.

There are 2 types of entries you will find in the GC log.

Partial GC: This clears the objects from young generation area by removing it from heap (if the object is no longer referenced by application) or moves the objects to the old generation area. The partial GC is represented as shown below

6930.574: [GC [PSYoungGen: 3099243K->15566K(3111424K)] 4976226K->1905642K(5208576K), 0.0220170 secs]

The above line means that the young generation was having an initial size of 3099243K. After the GC process completed, the young generation size reduced to 15566K. The unwanted objects were either removed or moved to the old generation area. The second section shows that the details about the entire heap (Young and Old Generation area). The size of heap before GC was 4976226K and after the GC the size reduced to 1905642K. The entire process of GC took 0.0220170 secs.

Full GC: This process performed the full GC as the old generation was reaching its capacity and the tenured objects from new generation area were not able to be moved from the new area to the old area. The Full GC is represented as shown below.

6966.094: [Full GC [PSYoungGen: 8110K->0K(3106624K)] [ParOldGen: 2069790K->1024980K(2097152K)] 2077901K->1024980K(5203776K) [PSPermGen: 49032K->48483K(131072K)], 2.0098750 secs]

The above line means that the Young generation occupancy changed 8110K to 0K due to the GC process. The old generation size before the GC was 2069790K and after the GC it was 1024980K. The logs also details about the permanent generation area too.

To generalize the above logs, the GC details are printed like this in the gc_log file

:Starting Capacity à Final Capacity

Taking the topic back to our application, after 5 hours, the GC log was showing only Full GC happening every 2 seconds. The reason was that the old generation was not getting cleared which was indicated by the similar starting capacity and final capacity of the old generation area in the GC log.

51655.720: [Full GC [PSYoungGen: 1857920K->217698K(2501824K)] [ParOldGen: 2023876K->2022817K(2097152K)] 3881796K->2240515K(4598976K) [PSPermGen: 53644K->53633K(131072K)], 1.4887940 secs]

51658.184: [Full GC [PSYoungGen: 1857920K->224477K(2501824K)] [ParOldGen: 2022817K->2022657K(2097152K)] 3880737K->2247134K(4598976K) [PSPermGen: 53643K->53598K(131072K)], 1.4882530 secs]

51660.675: [Full GC [PSYoungGen: 1857920K->236322K(2501824K)] [ParOldGen: 2022657K->2020841K(2097152K)] 3880577K->2257163K(4598976K) [PSPermGen: 53645K->53595K(131072K)], 1.9492500 secs]

51663.604: [Full GC [PSYoungGen: 1857920K->242417K(2501824K)] [ParOldGen: 2020841K->2020278K(2097152K)] 3878761K->2262696K(4598976K) [PSPermGen: 53607K->53597K(131072K)], 1.9473010 secs]

51666.424: [Full GC [PSYoungGen: 1857920K->217779K(2501824K)] [ParOldGen: 2020278K->2018873K(2097152K)] 3878198K->2236652K(4598976K) [PSPermGen: 53608K->53595K(131072K)], 1.4736700 secs]

51669.022: [Full GC [PSYoungGen: 1857920K->217271K(2501824K)] [ParOldGen: 2018873K->2018606K(2097152K)] 3876793K->2235878K(4598976K) [PSPermGen: 53654K->53595K(131072K)], 1.9685320 secs]

51671.963: [Full GC [PSYoungGen: 1857920K->226794K(2501824K)] [ParOldGen: 2018606K->2018585K(2097152K)] 3876526K->2245380K(4598976K) [PSPermGen: 53609K->53595K(131072K)], 1.5949040 secs]

51674.840: [Full GC [PSYoungGen: 1857920K->242015K(2501824K)] [ParOldGen: 2018585K->2017538K(2097152K)] 3876505K->2259553K(4598976K) [PSPermGen: 53647K->53597K(131072K)], 1.8560720 secs]

Diagnosing the Memory

The above log and inferences suggested that the application has memory leaks. We took different approaches and hit a roadblock in some approaches. The various approaches that were attempted are listed below.

To identify the memory leak issue, we need to figure out how many objects are getting created by the application and how many of them are removed after its use. For e.g.: If a byte stream is opened and not closed after its use, the byte array will continue to exist in the memory causing filling up of the old generation area. Since the byte array is present in the new area for long time, the objects will be moved to the old area. Hence the aim was to identify the objects that are occupying and filling the memory.

gcore

Using gcore, the process dump can be created. From the core dump, jmap process can generate a heap dump file. Using the heap dump file, the jhat process can generate a detailed histogram of objects in the heap. Our application was working on JDK5. gcore is a UNIX BSD utility which will generate the image of the running java process. The syntax to generate the core is

gcore

where pid is the process id of the java process. The file will be created by the name core.. The gcore process will create a file with a size which is equal to the resident memory used by the process. So if your process uses 3GB of resident memory, the core file created will be approximately 3GB and it might take 1-4 hours. While the gcore is running, all memory operation will be suspended on the process by the OS.

The core file generated is passed as parameter to the jmap process which will be used to generate the heap bin file. Since the core was generated for a process run on JDK5, the jmap of JDK5 should be used to generate the heap dump file. The syntax used is

/usr/java/jdk1.5.0_12/bin/jmap -heap:format=b `which java` core.5831

Attaching to core core.5831 from executable /opt/java/bin/java, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 1.6.0-ea-b52

Dumping heap to heap.bin ...

Heap dump file created

`which java` is used to get the path of the executable of java. The output will be created as heap.bin file. Using the heap.bin file, we can generate the heap histogram and details with the jhat utility introduced in JDK6.

/usr/java/jdk1.6.0/bin/jhat -stack true -J-d64 -J-mx10240m -port 8080 /heap.bin

The jhat can understand the heap dump created by the JDK5 and JDK4 processes (theoretically true but it did not work for us). Another point to note in using jhat is that it requires a lot of memory (approx 6-10GB for 2GB Heap file) and hence requires a 64bit JVM.

jhat (JDK 6 & above)

As mentioned before, we tried to generate the core file and generate the heap dump out of the core file. The jhat utility gave various exceptions while loading the heap dump created by the JDK5 process. So we used the JDK6 process to run our application. With JDK6, the approach we took is given below.

We first used jmap to generate the heap dump file. The syntax used is given below

/usr/java/jdk1.6.0/bin/jmap -dump:format=b,file=

After the heap dump file is created, we use the jhat utility to generate the heap description. The syntax used for the jhat is

/usr/java/jdk1.6.0/bin/jhat -stack true -J-d64 -J-mx10240m -port 8080 /heap.bin

The jhat utility will extract the data from the heap dump file and load it into the memory. Once the loading is complete, jhat will start a webserver at the port specified in the command shown above. The heap details can be accessed at the web URL

http://:8080/

Heap Histogram

All Classes (excluding platform)

Class Instance Count Total Size

class [B 337060 1428530365

class [C 3708107 302392746

class java.lang.String 3653039 73060780

class [I 52573 51248160

class xh7_6_13.yl 321018 33064854

class [Ljava.util.HashMap$Entry; 78852 13199256

class [Ljava.lang.Object; 72781 12525120

class java.util.HashMap$Entry 156231 4374468

The [represents array of objects of type mentioned as the next word.

class [C is char[]

class [B is byte[]

class [Z is boolean[]

class [S is short[]

class [I is int[]

class [J is long[]

class [D is double[]

The details like who are referring to each object are also present inside the heap histogram details. This is found by using the referrer and reference property of each type of object. Using this data, we can identify the objects that are loaded into the memory and the objects that are unintentionally lingering in the memory. Once we identify the object, we can track the code to remove the unwanted references.

jmap

With JDK6 and above, the jmap process can directly print the heap histogram as a text file. This is much easier and can give early indications of memory leak. Since the output is a text file, more details like who loaded, who is referencing it will not be present. For the details that are missed in the jmap histogram output, jhat need to be used.

Memory Profiler

We used a commercially well known memory profiler and it did not serve the purpose.

Though the intention of the document is not to show how the issue was fixed, few reviewers felt that it should be added. From the heap histogram, it was evident that the byte array was consuming almost 1.4GB of the available 2GB space of the Old generation area. The remaining 0.6 GB was occupied by a cache, which was designed to do it that way. The byte array was occupying memory as one of the byte streams was not closed by the application.

The above cases work with SUN JDK. For other JVM’s there are other tools like HEAP Analyzer and MDD4J.

Sunday, July 6, 2008

Pass by Reference still?

Snippet1

public class Test {

public static void main(String[] args) {

A a = new A();

System.out.println(a.j);

xyz(a);

System.out.println(a.j);

}

private static void xyz(A a) {

a = new A(); //watch this line

a.j=20;

}

}

class A {

public int j = 10;

}

Output:

10

10

Snippet2

public class Test {

public static void main(String[] args) {

A a = new A();

System.out.println(a.j);

xyz(a);

System.out.println(a.j);

}

private static void xyz(A a) {

//a = new A(); //commented

a.j=20;

}

}

class A {

public int j = 10;

}

Output:

10

20

In snippet 2, did you notice that the updated value from the method xyz is printed in the main method? In snippet 1, the updated value from the xyz method is not reflected in the main method and hence the updated value is not printed. There are reasons behind this behavior.

In the main method of snippet 1, an object A is created at memory location say “XYZ”. The memory location of the object is passed as parameter to method xyz. In xyz method, the statement a= new A(), creates a new A object at a different memory location say “PQR”. The value of the variable “j” in the object at memory location “PQR” is then updated to 20. When the method xyz returns, the main method still refers to the “XYZ” memory location and hence prints the original value of 10 and not 20.

In the main method of snippet 2, as in snippet 1, the object A is created at memory location “XYZ”. The memory location of the object is passed as parameter to method xyz. In xyz method, the value of the variable “j” in the object at memory location “XYZ” is then updated to 20. When the method xyz returns, the main method still refers to the “XYZ” memory location and hence prints the updated value of 20.

Try making the variable “a” as class level variable and static in nature, you will find the difference. You should be able to identify the difference.

Sunday, June 15, 2008

Demystifying Java Object

This blog attempts to explain about various methods that should be overridden and under which circumstances. Every class in java has Object class as the base class. Object class has methods defined in it. Some of them can be overridden while the remaining of them cannot be overridden (they are defined as final in the Object class like wait , notify etc). The methods that can be overridden are provided with a basic implementation so that for all basic purposes, the basic implementation can be used. In this document, we will be discussing about the non-final methods which can be overridden by the subclasses.


Non-Final Methods
clone
equals
finalize
hashCode
toString


In the following sections, we will discuss about the non-final methods present in the Object class. For every method, we will navigate through three sections
· Java-doc and Default Implementation – One liner crisp documentation as per java-doc will be quoted. The section will also detail about he basic implementation provided by the Object class.
· Usage – The various possible usages of the method will be detailed.
· Overriding Implementation - Possible implementation detail should the subclass decide to override the basic structure provided by the Object class.


1. clone


Java-doc and Default Implementation
As per javadoc “Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object”. The default implementation will create a separate copy of the object and return to the caller. The default implementation is implemented as a native method.


Usage
The clone method is used in multiple scenarios
1. It is used to create a copy of the object so that application can work on different objects independently.
2. It can be used to ensure that the application doesn’t create multiple copies of the object and work on them independently. This is implemented by throwing an exception in the clone implementation method.


Overriding Implementation
If the object is made of only immutable objects and primitives, the clone method implemented in the Object class is sufficient for creating a complete clone of the object. It will create a new copy of the object and return it. If the object is composed of mutable objects, the clone method should be implemented to get a complete clone of the object (refer to shallow copy and deep copy procedures).
The implementation should navigate through the structure of the object and clone all of the composed mutable objects. It should replace the reference of the mutable objects within the object with a reference to its cloned copies. As a general rule, the clone method should be implemented if the object is composed of mutable objects and a complete or deep clone is required.
If the object which needs to be cloned is composed of large number of mutable objects, another approach create a clone is to perform serialization and de-serialization..

Clone method is also used in circumstances where a new copy of the object should not be created by cloning the object. In such a scenario, the clone method should be implemented and a CloneNotSupportedException should be thrown. This approach is useful while implementing caches and singleton classes.

2. finalize


Java-doc and Default Implementation
As per javadoc “Called by the garbage collector on an object when garbage collection determines that there are no more references to the object”. The default implementation of finalize method in the Object class does not perform any special function.


Usage
The garbage collection process consists of the mark and sweep process. The GC process will identify the objects that are not reachable from any other live threads. The GC will invoke the finalize method on all of the identified objects. After this, the GC process will again iterate through the objects to ensure that it is not reachable from any of the live threads. Once the object is identified as not reachable from any live threads, object is discarded.
This finalize method is hence invoked by the garbage collector when the object is marked for deletion by the GC Process. The order in which the finalize method on the marked objects will be invoked is not guaranteed. Also any garbage collection thread can invoke the finalize method on the marked object. This means, if there are 10 objects that are marked for garbage collection, the JVM can invoke the finalize method on these 10 objects in any order and multiple GC threads can perform the invocation on different objects at the same time.

Any unhandled exception thrown from this method will be ignored by the JVM and the finalize process on that object will terminate. It is also guaranteed that the finalize method will be invoked only once in the life cycle of the object.


Overriding Implementation
The finalize method should be implemented by the class if some clean up process needs to be performed only before the object is being completely evicted from the JVM. The finalize method can also make the object available again for use by other threads i.e. bring back from garbage collection process.

Care should be taken to avoid cyclic references within the objects that are marked for garbage collection process. This might bring in cyclic loops. The finalize method should be implemented keeping performance of the garbage collection process in mind. The finalize process can delay the garbage collection processing if implemented incorrectly.

3. toString


Java-doc and Default Implementation
Javadoc states that “Returns a string representation of the object.” The String returned from the toString method in the Object class is formed by appending the name of the class of which the object is an instance + “@ “ + the unsigned hexadecimal representation of the hashCode of the object.


Usage
The toString method is generating a String representation of the object. This will be useful during debugging and logging operations. AbstractCollection class has a decent toString implementation in which it iterates through all of the objects in the collection and invokes the toString on the contained objects. This way a meaningful representation of the collection object is returned to the user when the toString method is invoked


Overriding Implementation
The toString implementation should ensure that a meaningful string representation of the object is returned. For a composite object, the toString method can recursively invoke the toString method of all of the composed objects and generate the string representation. For collections, we can iterate through the objects and generate a string representation of the object.

4. equals


Java-doc and Default Implementation
As per javadoc “Indicates whether some other object is "equal to" this one”. The default implementation of equals method will check if the memory reference of an object and the compared object are the same. It performs a memory location comparison and not value comparison. The method definition of equals method in the Object class is

public boolean equals(Object obj) {
return (this == obj);
}
This method compares the memory address of the “obj” with the memory address of “this” object


Usage
The equal method is used to check the equality between two objects. The equals method is overridden in many of the commonly used classes like String class. In String class, the equals method will return true if the two objects point to same memory location or if the two string objects has the same sequence of characters.

Consider the below samples
Case 1:
String s1 = “Vijith”
String s2= “Vijith”

System.out.println(s1==s2 ) -> true
System.out.println(s1.equals(s2) ) -> true

The s1 == s2 is returning true because the two strings are pointing to the same memory location. In the s1.equals(s2) method, the method returns true because the s1 and s2 have same set of characters.

Case 2:
String s1= new String(“Vijith”);
String s2 = new String(“Vijith”);

System.out.println(s1==s2 ) -> false
System.out.println(s1.equals(s2) ) -> true

The s1==s2 will return false because s1 and s2 are pointing to different memory locations. A new operator will create the string objects pointing to different memory locations.
The s1.equals(s2) return true as the sequence of characters are same for s1 and s2 string object. The memory location of s1 and s2 are different in this case and still returns true as the default implementation of equals method in the Object class is overridden with a different implementation in the String class. The equals method of String class checks for the sequence of characters.


Overriding Implementation
The equals method should be implemented carefully. There are set of properties to be maintained when the equals method is overridden. For non-null objects, it should be symmetric, transitive, reflexive, consistent and x.equals(null) should return false.

Another rule of objects is that two equal objects should retrun the same hashCode. Hence overriding the equals method would generally need to override the hashCode method too.

A sample equal method implementation is shown below. In this method , the equals method compares the value of the key of two objects and if they return the same value, true is returned.

public boolean equals(Object o){
if(this == o)return true;
if (o==null)return false;
if(this.key1 == null ((MyObject)o).key1 == null )return false;
if (this.key1.equals(((MyObject)o).key1)){
return true;
}else{
return false;
}
}


Another significant place where the equals as well as the hashCode method overriding is important is the primary keys of an Entity Bean. The hashCode method should return well distributed hashCode against which the Entity Bean will be stored in the HashMap. If two objects return same hashCode, then the HashMap will use the equals method to determine the correct Object. I will be detailing the hash lookup in some other article at a later point.


5. hashCode


Java-doc and Default Implementation
As per javadoc “Returns a hash code value for the object.”. The default implementation of hashCode method will return the integer representation of the memory reference of an object. The method is implemented as a native method in the Object class.


Usage
hashCode method is used for the benefit of implementations that depend on the hashing mechanism like HashMap, HashTable. This method is not invoked nor has direct relationship with the equals method except that the default implementation of hashCode and the equals method depends on the memory location of the object.
The hashCode method is invoked when the object is added or accessed in any implementation that uses hashing mechanism like HashMap. When the object is inserted into a HashMap, the hashCode is evaluated to determine the location to which the object needs to be added. If two objects return same hashCode, then equals method is used to identify if the keys are equal. A hashCode implementation can make the performance of the HashMap better or worse based on the implementation. A well distributed hashCode can be a good implementation while returning a constant value like “1” will be a poor implementation to perform a hash lookup.


Overriding Implementation
hashCode should be overridden to return a well distributed and repeatable hashCode for the object. The HashMap will evaluate the hashCode of the key to determine the object. If the hashCode lookup returns more than one object with the same hashCode, the equals method will be used to determine the correct object.

In the below implementation, the hashCode method appends the various internal fields to create a string object. The hashCode of the resultant string is returned as the hashCode for this object.

public int hashCode(){
StringBuffer sb = new StringBuffer();
sb.append(internal_value1);
sb.append(internal_value2);
sb.append(internal_value3);
String str = sb.toString();
retrun str.hashCode();
}