comments powered by Disqus

How to fix...

On this page, we've collected together a few common exceptons and problems that occur in Java programs. We look at how they are typically caused and resolved. Topics currently covered:

If you think there's some other problem that should be included here, then let us know by posting a message to the Javamex forum.

OutOfMemoryError

The most common cause of an OutOfMemoryError is that your program is running out of heap space: that is, the memory space set aside for the objects that your program creates. There are usually two possibilities:

To increase the heap size, you can add a heap size setting to the Java startup command used to launch your program. For example:

java -Xms128m -Xmx512m MyClass

will tell Java to initially allocate a minimum heap space of 128 MB, and allow this to grow up to 512 MB. (In reality, there is not usually a "single heap" in modern JVMs, but rather the space you allocate is portioned into different areas for newly created objects, longer-lasting objects etc. But many programs won't need to worry about this.) Because of the overhead of growing the heap when it gets full, you should set a "decent" minimum size if you know that your application is likely to be memory-hungry.

Note too that successive JVMs have got more sensible about allocating a sensible heap size by default. Early JVMs tended to allocate what is now a fairly piddly amount by default, e.g. 32 MB. But from Java 5 onwards, the default allocation has been significantly improved, and makes it easier in cases where you're bypassing the command line altogether (e.g. on systems where you can double-click on an executable Jar to run it). So if you're running an earlier JVM, one solution may simply be to upgrade your JVM.

If you're running in an IDE such as Eclipse, you generally need to find the place in the Project Settings where you can specify "VM arguments".

Heap size limits

On 32-bit machines, the maximum heap size is typically just under 2 GB (Windows with default settings), or just under 3 GB on UNIX-like systems. Technically, the maximum heap size is determined by the maximum amount of contiguous memory space that the Java process can allocate. Under windows, this usually ends up being about 1650-1700 MB out of the theoretical 2GB memory space.

This limit does not generally apply to 64-bit machines provided that you are genuinely running a 64-bit JVM.

NullPointerException

This is one of the most common exceptions to occur in Java programs. It happens when you try to call a method on a null object reference (or when you try to access fields on one). So let's say we have some code such as the following:

int noFiles = dir.listFiles().length;

If we get a NullPointerException on this line, it means that either dir is null, or that the result of listFiles() (which is supposed to be an array of File objects) is null. In principle, without knowing more about the surrounding code, either of these who objects could be the one that is null. We need to use a process of logic and elimination to try and work out which one is null. If the line was as follows:

int noFiles = fileList.length;

then we would have to follow our program back to where fileList was created (or where the variable was last set) and work out why it could be being set to null.

Because cases like this can be ambiguous or because it can be difficult to trace back to the origin of a null object, it is good practice to check for nulls as early on as they can be eliminated. For example, at the beginning of a method that we write, we can put in an explicit null check:

private int getFileListLength(File[] files) {
  if (files == null)
    throw new NullPointerException("File list cannot be null");
}

Now, if the file list is null, we'll get a null pointer exception "as soon as the problem can be detected", rather than later on in the code when it may be more difficult to work out the source of the null.

StackOverflowError

If your Java program throws a StackoverflowError, if usually means one of two things:

In the second case, which is probably more common, you need to correct the algorithm so that it doesn't infinitely call itself. However, if you are sure that your algorithm doesn't contain a bug, but you just need to allow it to recurse to a greater depth (bearing in mind that with an average number of parameters, you should generally be able to go to a depth of between 1000 and 2000 recursive calls), then you need to increase the stack size of the thread that is running the algorithm. There are essentially two ways to do this:

The second way is often preferable. To do so, we use the version of the Thread constructor that takes a stack size. For example, the following will run myMethod(), but give it 2MB of stack space:

Runnable task = new Runnable() {
  public void run() {
    myMethod();
  }
};
Thread thr = new Thread(null, task
  "ExtraStackThread", 1024 * 1024 * 2);
thr.start();
thr.join();

StreamCorruptedException

We treat this error in a separate page on StreamCorruptedException.

EXCEPTION_ACCESS_VIOLATION

In rare circumstances, a Java program could stop with a message similar to the following:

# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c042340, pid=1743, tid=122
#
# Java VM: Java HotSpot(TM) Client VM (1.5.4_02)
# Problematic frame:
# C [ntdll.dll+0x2430]

Essentially, Java will stop with a message such as the above if a "serious" error occurs that means the JVM can't continue to function. Usually, the most discriminating line is the first mention of a DLL, such as the line in bold above. The source of the error could be any of the following:

If you're not sure what to do but are not using the latest version of the JVM for your system, then a good first course of action is usually to upgrade your JVM. If the bug is in some other DLL, e.g. a printer driver, database driver, graphics driver etc, then it is best to see if you can upgrade the component in question.

If the error is occurring in some native code that you have written, then you need to find out which line of code corresponds to the offset mentioned (in this case, 0x2430, although the DLL isn't one of ours in this example). Usually you can tell your compiler to generate a "map file" that gives a list of code offsets per line number. Because of compiler optimisations, line numbers may be approximate.


Latest update: 9 December 2012.