java.lang.OutOfMemoryError: Java heap space

Java applications are allowed to use a limited amount of memory. This limit is specified during application startup. To make things more complex, Java memory is separated into two different regions. These regions are called heap space and permgen:

OutOfMemoryError: Java heap space

The size of those regions is set during the Java Virtual Machine (JVM) launch by specifying parameters such as -Xmx and -XX:MaxPermSize. If you do not explicitly set the sizes, platform-specific defaults will be used.

So – the “java.lang.OutOfMemoryError: Java heap space” error will be triggered when you try to add more data into the heap space area, but there is not enough room for it.

Note that there might be plenty of physical memory available, but if the heap size limit for this Java program has been hit, the “java.lang.OutOfMemoryError: Java heap space” error is thrown.

Cause of java.lang.OutOfMemoryError

There most common reason for the java.lang.OutOfMemoryError: Java heap space error is simple. You are trying to fit an XXL application into a S-sized Java heap space. That is – the application just requires more Java heap space to operate normally. Other causes for this OutOfMemoryError message are more problematic and are caused by a programming error:

  • Spikes in usage/data volume. The application was designed to handle a certain amount of users or a certain amount of data. Now, when the number of users or the volume of data suddenly spikes, the operation which functioned normally before the spike ceases to respond and triggers the java.lang.OutOfMemoryError: Java heap space error.
  • Memory leaks. A particular type of programming error will lead your application to constantly consume more memory. Every time the leaking functionality of the application is used it leaves some objects behind into the Java heap space. Over time the leaked objects consume all of the available Java heap space and trigger the already familiar java.lang.OutOfMemoryError: Java heap space error.

Can’t figure out what causes your OutOfMemoryError?
Plumbr to the rescue.

Example of java.lang.OutOfMemoryError

Trivial example

The first example is truly simple – the following Java code is trying to allocate an array of 2M integers. When compiled and launched with 12MB of Java heap space (java -Xmx12m OOM), it fails with the “java.lang.OutOfMemoryError: Java heap space” message. With 13MB Java heap space the program runs just fine.

class OOM {
  static final int SIZE=2*1024*1024;
  public static void main(String[] a) {
    int[] i = new int[SIZE];
   }
}

Memory leak example

Second and more realistic example is of a memory leak. In Java, when developers create and use new objects e.g. new Integer(5), they don’t have to allocate memory themselves – this is being taken care of by the Java Virtual Machine (JVM). During the life of the application JVM periodically checks which objects in memory are still being used and which are not. Unused objects can be discarded and the memory reclaimed and reused again. This process is called garbage collection. The corresponding module in JVM taking care of the collection is called Garbage Collector (GC).

Java’s automatic memory management relies on GC to periodically look for unused objects to remove them. Simplifying a bit we can say that a memory leak in Java is a situation where some objects are no longer used by the application but GC fails to recognize it. As a result these unused objects remain in Java heap space indefinitely. This pileup will eventually trigger the “java.lang.OutOfMemoryError: Java heap space” error.

Now it is fairly easy to construct a Java program that satisfies the definition of a memory leak:

class KeylessEntry {
 
   static class Key {
      Integer id;
 
      Key(Integer id) {
         this.id = id;
      }
 
      @Override
      public int hashCode() {
         return id.hashCode();
      }
   }
 
   public static void main(String[] args) {
      Map m = new HashMap();
      while (true)
         for (int i = 0; i < 10000; i++)
            if (!m.containsKey(new Key(i)))
               m.put(new Key(i), "Number:" + i);
   }
}

When you execute the code above you would expect it to run forever without any problems – after all, the naive caching solution built should only expand the underlying Map to 10,000 elements, as after that all the keys are already present in the HashMap. However, this is not the case – the elements keep being added as the Key class does not contain a proper equals() implementation next to its hashCode().

Thus, over time, with the leaking code constantly used, the “cached” results consume a lot of Java heap space. Whenever the leaked memory fills all of the available memory in heap region and garbage collection is not able to clean it the “java.lang.OutOfMemoryError:Java heap space” is thrown.

The solution would be easy – add the implementation for equals() method similar to the following sample and you’re good to go. But before you manage to find the cause, you have definitely spent lost some precious brain cells.

@Override
public boolean equals(Object o) {
   boolean response = false;
   if (o instanceof Key) {
      response = (((Key)o).id).equals(this.id);
   }
   return response;
}

Solution for java.lang.OutOfMemoryError

The first solution should be obvious – when you have ran out of a particular resource, you should increase the availability of such a resource. In our case: when your application does not have enough Java heap space memory to run properly, fixing it is as easy as altering your JVM launch configuration and adding (or increasing if present) the following:

-Xmx1024m

In the example above the application is given 1024MB of Java heap space. You can use g or G for GB, m or M for MB, k or K for KB. For example all of the following are equivalent to saying that the maximum Java heap space is 1GB:


    java -Xmx1073741824 com.mycompany.MyClass
    java -Xmx1048576k com.mycompany.MyClass
    java -Xmx1024m com.mycompany.MyClass
    java -Xmx1g com.mycompany.MyClass

In many cases, providing more Java heap space is not exactly going to solve the problem. For example, when facing a memory leak you are just postponing the java.lang.OutOfMemoryError: Java heap space error, not solving it. Also, when increasing the amount of Java heap space you also tend to increase the length of GC pauses affecting your application throughput or latency.

If you wish to solve the underlying problem with the Java heap space instead of masking the symptoms, you have several tools at your disposal. Debuggers, profilers, heap dump analyzers – the choice is yours. But whenever you wish to check whether your application is free from memory leaks and runs on optimal heap configuration, try out Plumbr, a memory leak detection tool, for free.

Can’t find the cause of your OutOfMemoryError?
Plumbr to the rescue!