Monday, January 18, 2010

OutOfMemoryError (on HeapSpace, PermGen) and JVM Performance Tuning

HeapSpace OutOfMemoryError:

"Exception in thread "main" java.lang.OutOfMemoryError: Java heap space"

Most of you would have encountered this error before. This means JVM's usage of heap space exceeded what you specified in -Xmx vm argument or the default max heap size (if you did not specify one).

When you get this error, before you increase your -Xmx value, make sure to profile your application and see whether the usage is justified or if there is any memory leak. See below section on profiling tools.

PermGen OutOfMemoryError:

"java.lang.OutOfMemoryError: PermGen space"

Sometimes, you would also get a different kind of out of memory error. In JVM heap, there are different generations - Young, Tenured and PermGen. Young and tenured generations are where the regular objects from your application are stored. Size of young + tenured generation is controlled by -Xmx variable you saw above. PermGen is where JVM stores string pool, metadata about your application's classes etc.,

This error would normally happen only if your application loads a large number of classes, but is not unloading for some reason, which could be either legitimate or a memory leak. Also, make sure to check if your application heavily uses String.intern(), which could also contribute to this error.

JVisualVM provides a good insight on how your permgen grows and how many classes are loaded/unloaded at any point in time. You could also use JConsole to find this, although it is more clear and easy to find in JVisualVM. These tools only show how many classes are loaded/unloaded, but if you want to find out which classes are loaded/unloaded, you can use JVM debugging options like -XX:+TraceClassLoading and -XX:+TraceClassUnloading. They print the actual full class name which is loaded/unloaded. You can also use -XX:+PrintGCDetails and see how the permgen size grows/shrinks.

If your profiling shows that it is legimiate, increasing the max permgen size would avoid this issue. For example, this vm argument -XX:MaxPermSize=128m would set the max perm size to 128MB.

Related articles/resources on PermGen:

http://www.brokenbuild.com/blog/2006/08/04/java-jvm-gc-permgen-and-memory-options/
http://www.freshblurbs.com/explaining-java-lang-outofmemoryerror-permgen-space
http://www.alessandroribeiro.com/?q=en/node/41
http://www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.html
http://kohlerm.blogspot.com/2009/01/is-javalangstringintern-really-evil.html

Performance Tuning:

If you are setting max heap size or max permgen size, it is a good idea to also set min heap size (-Xms) and min permgen size (-XX:PermSize). This could avoid unnecessary resizing of the heap and might improve performance. Make sure these are set to at least what your application needs to start. This would avoid heap resizing during start up and would improve your application start up time. You could also set min and max to be the same to avoid resizing at all, but you should be very cautious and make a good choice of heap size in this case.

You could use some of the advanced performance options like -XX:NewRatio, -XX:SurvivorRatio etc., More details on other available performance options can be found here:
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#PerformanceTuning

Before using these advanced options, it is good to profile and see what are the typical allocations in young and tenured generation for your application. This depends on the infant mortality of your application's objects i.e how long the objects live in your application. It could turn out that they are dependent on user's actions and features they use in the application. In that case, it is better not to tune them in the deployed application by default and instead profile and tune them on a per case basis, if a particular client have issues etc.,

Related articles/resources on Performance Tuning:

http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html
http://java.sun.com/docs/hotspot/gc5.0/ergo5.html
http://java.sun.com/docs/hotspot/gc1.4.2/faq.html

Profiling Tools:

You could use the free tools which come with JDK - JConsole, JVisualVM, JMap, JHat, JVMStat etc., These could be found in your JDK bin directory. You could also use TPTP, Eclipse Memory Analyzer etc., which are also free. To download Eclipse Memory Analyzer plugin, you can point to the galileo update site - http://download.eclipse.org/releases/galileo and download General Purpose Tools->Memory Analyzer plugin.

Or, if you can afford, you could use these commercial profiling tools - JProfiler, JProbe, YourKit etc.,

You could also use the debugging options in vm args to get more information. Some common debugging options are -XX:-HeapDumpOnOutOfMemoryError, -XX:-PrintGCDetails, -XX:-TraceClassLoading, -XX:-TraceClassUnloading etc., For more information on other available debugging options, see here - http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

Sunday, January 10, 2010

Updating UI in Eclipse RCP

Introduction:

In Eclipse RCP, generally the code is executed in UI thread most of the time. Running long operations here would freeze UI. I've blogged about this in my previous post. So, the solution is to either spawn off a separate thread or if you want to show progress to the user, use Jobs API as illustrated in point 5 in previous post and execute long running operation there. But, if you want to update UI while the code is running in non-UI thread, you need to make sure that it is done via UI thread. Otherwise, you will get bizzare behavior during runtime.

Swing:

If you are a Swing programmer, you are already familiar with this concept. In Swing, generally the code is run in event dispatch thread and all UI update operations need to be done from this thread. If you want to update UI while running long operations in another thread, you need to use SwingUtilities.invokeLater or SwingUtilities.invokeAndWait for this purpose. You can read more about it from this post.

Eclipse RCP:

In Eclipse, the idea is similar. All UI update operations need to be done from UI thread. So, if you want to update UI from other threads, you need to use Display.asyncExec or Display.syncExec method.

Display.getDefault().asyncExec(new Runnable() {
public void run() {
// Update UI here
}
});
System.out.println("This could be printed before run method finishes...");

Display.asyncExec would execute the run() method asynchronously (similar to invokeLater) i.e the thread which calls executes asyncExec line would get executed in parallel with the run() method.

Display.getDefault().syncExec(new Runnable() {
public void run() {
// Update UI here
}
});
System.out.println("This would be printed after run method finishes...");

Display.syncExec follows similar syntax and would execute the run() method synchronously (similar to invokeAndWait) i.e the thread which calls executes syncExec line would get executed wait until run() method finishes.

In general, it is good to use asyncExec, unless you specifically want the calling thread to block.



Saturday, January 9, 2010

Eclipse RCP - Prevent UI freezing while running long operation

According to this blog post, the number one mistake which Eclipse developers do is running long operations in UI thread. I certainly agree this is a terrible mistake. Doing this will freeze the UI and lead to bad user experience. As stated in this blog, users need to make sure that long running operations run in a separate non-UI thread. But, in Eclipse, it is not very clear when we are in UI thread and when we are not. I attempt to clarify that in this post and explain few related things in more detail.

1) Any regular code, say in createPartControl of a view or an editor are executed in UI thread. Don't do any long operations in this. Spawn off a separate thread and do them there.

2) Code inside any SWT listener methods are also executed by UI thread. This is also stated in the eclipse-tips blog.

3) Code inside run() method in your Action class is also executed by UI thread.

4) Code inside run() method in your Handler class is also executed by UI thread.

5) If you use Jobs API to run long running operations, your code would typically look like this:
Job job = new Job("Long Job") {
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("Job started...", 10);
// Run long running task here
monitor.done();
return Status.OK_STATUS;
}
};
job.setUser(true);
job.schedule();

Here the code inside run() method is in not in UI thread and you are in worker thread. Running long tasks is fine here. But, what if you want to update UI while your long running task is running. You should use either asyncExec or syncExec for this purpose. I will explain about them in more detail in my next post. If not, you will have problems while running your application.

6) If you just want to show busy indicator while running long operation, your code would typically look like this:

BusyIndicator.showWhile(PlatformUI.getWorkbench().getDisplay(), new Runnable() {
public void run() {
// Long operation goes here
}
});

Unlike point 5, here the code inside run() method is not executed in worker thread. The code is run by UI thread only. So, make sure not to execute too long running operations here.