java.lang.OutOfMemoryError: Metaspace

Java applications are allowed to use only a limited amount of memory. The exact amount of memory your particular application can use is specified during application startup. To make things more complex, Java memory is separated into different regions, as seen on the following diagram:

metaspace error

The size of all those regions, including metaspace area, can be specified during the JVM launch. If you do not determine the sizes yourself, platform-specific defaults will be used.

So – the “java.lang.OutOfMemoryError: Metaspace” message indicates that the Metaspace area in memory is exhausted.

Cause of java.lang.OutOfMemoryError

If you are not a newcomer to Java landscape, you might be familiar with another concept in Java memory management called PermGen. Starting from Java 8, the memory model in Java was significantly changed. A new memory area called Metaspace was introduced and Permgen was removed. This change was made due to variety of reasons, including but not limited to:

  • The required size of permgen was hard to predict. It resulted in either under-provisioning triggering java.lang.OutOfMemoryError: Permgen size errors or over-provisioning resulting in wasted resources.
  • GC performance improvements, enabling concurrent class data deallocation without GC pauses and specific iterators on metadata
  • Support for further optimizations such as G1 concurrent class unloading.

So if you were familiar with PermGen then all you need to know as background is that – whatever was in PermGen before Java 8 (name and fields of the class, methods of a class with the bytecode of the methods, constant pool, JIT optimizations etc) – is now located in Metaspace.

As you can see, Metaspace size requirements depend both upon the number of classes loaded as well as the size of such class declarations. So it is easy to see the main cause for the “java.lang.OutOfMemoryError: Metaspace“ is: either too many classes or too big classes are being loaded to the Metaspace.

Can’t figure out what causes your OutOfMemoryError?
Read more.

Example of java.lang.OutOfMemoryError

As seen in the causation section, Metaspace usage is strongly correlated with the number of classes loaded into the JVM. The following code serves as the most straightforward example:

public class Metaspace {
	static javassist.ClassPool cp = javassist.ClassPool.getDefault();

	public static void main(String[] args) throws Exception{
		for (int i = 0; ; i++) { 
			Class c = cp.makeClass("eu.plumbr.demo.Generated" + i).toClass();
		}
	}
}

In this example the source code is iterating over a loop and generating classes at the runtime. All those generated class definitions end up consuming Metaspace. Class generation complexity is taken care by the javassist library.

The code will keep generating new classes and loading their definitions to Metaspace until the space is fully utilized and the “java.lang.OutOfMemoryError: Metaspace” is thrown. When launched with -XX:MaxMetaspaceSize=64m then on Mac OS X the Java 1.8.0_05 will die at around 70,000 classes loaded.

Solution for java.lang.OutOfMemoryError

The first solution when facing the OutOfMemoryError due to Metaspace should be obvious. If we have exhausted the Metaspace area in the memory we can increase its size. This solution is indeed helpful if you just have not given your JVM enough elbow room. So alter your application launch configuration and increase the following:

-XX:MaxMetaspaceSize=512m

This configuration parameter is indicating to the JVM that Metaspace is allowed to grow up to 512 MB before complaining in the form of OutOfMemoryError.

Another solution is even simpler at first sight. You can remove the limit on Metaspace size altogether by deleting this parameter. But pay attention to the fact that by doing so you can introduce heavy swapping and/or reach native allocation failures instead.

Before calling it a night, be warned – more often than not usage of the recommended “quick fixes” means you are just masking the symptoms by hiding the “java.lang.OutOfMemoryError: Metaspace” and are not tackling the underlying problem. If your application is either leaking memory or is just loading something unreasonable to Metaspace you have not actually improved anything, you just postponed the problem.

Can’t figure out what causes your OutOfMemoryError?
Read more.