What is an OutOfMemoryError and how do I debug and fix it

My Java program threw an OutOfMemoryError. How do I debug and fix this problem?


Many newcomers to Java struggle to cope with an OutOfMemoryError. This is an attempt to create a canonical question that will answer the most frequently asked questions about an OutOfMemoryError. I'm creating this new question, rather than adapting one of the numerous previous questions about a OutOfMemoryError because those questions and their answers are tightly coupled to the particular problem a person had.

This question is distinct from general advice on debugging exceptions because the cause of the problem is not always on the call stack, and specific advice is necessary.


Solution 1:

An OutOfMemoryError is an exception thrown by the Java Virtual Machine (JVM) because it needs to allocate memory for a (new) object, but insufficient memory is available for the object. The JVM will have first tried to free memory used by dead objects, by running the garbage collector.

As an OutOfMemoryError is a VirtualMachineError, the JVM is permitted to throw it at any time, although it must try to release memory through garbage collection first.

However, in practice it is likely to be thrown from a new statement that tried to create an object for which memory could not be allocated. Therefore, you should first examine the stacktrace associated with the exception for clues about the cause of the problem, as you would for any other exception.

  • If the exception is thrown from an attempt to allocate an array (such as int[] values = new int[n]), the cause could be that you are trying to create an excessively large array (n is too large). Have you made a mistake in the calculation of the size of array you need?
  • If the exception is thrown from an attempt to allocate an array in a method of a container class written by someone else, the cause could be that your code is asking the container to store an excessive number of things. Methods such as ArrayList.reserve(int) and HashMap(int) must allocate storage for future use. Have you made a mistake in the calculation of the size of container you need?
  • If the exception is thrown from inside a loop, the cause could be that the code has looped too many times. Is your loop termination condition correct? If it is a for loop, are you asking it to loop the correct number of times?

If the stacktrace does not provide enough clues, you could try using a heap profiler. That is a monitoring program that enables you to examine the memory used for objects while the program runs, or examies a heap dump written when the program exits. It can provide information about the sizes, number and classes of objects stored in memory.

The JVM has a finite amount of memory made available to it. You might conclude that you program is behaving correctly, but just needs more memory to run than has been made available to it. If you do not explicitly tell the JVM how much memory to use, most implementations will choose a sensible default amount based on the amount of RAM that your computer has, but that amount could be too small for your program. Command line options for the JVM can control how much memory is made available. For most JVM implementations, the most important of those options are -Xmx and -Xms.

Solution 2:

To debug an OutOfMemoryError, invoke the JVM with the -XX:+HeapDumpOnOutOfMemoryError option, which will cause a heap dump to be written out when an OutOfMemoryError occurs. Then use a tool like VisualVM, jhat, or fasthat to look at the heap dump.

You can also generate a heap dump manually at any time by using jmap with the -dump option.

Disclosure: I'm the maintainer of fasthat, which is a fork of jhat.