How to solve java.lang.OutOfMemoryError: Compressed class space error

This article discusses how to solve the error “java.lang.OutOfMemoryError: Compressed class space error” which is an OutOfMemory error that can pop up on a 64-bit platform.

Starting with Java 1.8, loaded classes are confined to a native space called the “Compressed Class Metadata Space” or CCMS.

The default size for the Compressed Class Metadata Space is 1Gb of memory, except you specify a different value by passing an argument on the JVM command line. When classes are being loaded by the classloader, the JVM tries to allocate the metadata on the CCMS. If JVM cannot make room for the CCMS arena, the Compressed class space error is thrown. So in most cases, the simplest solution is to increase the value for CompressedClassSpaceSize, for example to 2 GB:

-XX:CompressedClassSpaceSize=2g

The variables which we should consider are however two:

  • MaxMetaspaceSize is the maximum amount of memory that can be committed to the class metadata and committed compressed class spaces combined. If you don’t specify this flag, the Metaspace will dynamically re-size depending of the application demand at runtime.
  • CompressedClassSpaceSize is the amount of virtual memory reserved just for the compressed class space.

As a rule, you should set the MaxMetaspaceSize to be larger than the CompressedClassSpaceSize as in the following example:

-XX:MaxMetaspaceSize=512m -XX:CompressedClassSpaceSize=256m 

We can check the values for both variables with ‘jcmd’ passing as arguement the PID of the Java process and “VM.metaspace”:

 jcmd 13966 VM.metaspace

  . . 
MaxMetaspaceSize: 512.00 MB
InitialBootClassLoaderMetaspaceSize: 4.00 MB
UseCompressedClassPointers: true
CompressedClassSpaceSize: 256.00 MB

As you can see, our proposed CompressedClassSpaceSize has been committed in the JVM.

Conversely, if MaxMetaspaceSize is set to a lower value than than CompressedClassSpaceSize, the JVM will self-adjust the CompressedClassSpaceSize based on the following formula:

CompressedClassSpaceSize = MaxMetaspaceSize – 2 * InitialBootClassLoaderMetaspaceSize

For example, we will be using the following JVM options:

-XX:MaxMetaspaceSize=256m -XX:CompressedClassSpaceSize=512m

Running again jcmd against the Java process reveals the actual value for CompressedClassSpaceSize:

MaxMetaspaceSize: 256.00 MB
InitialBootClassLoaderMetaspaceSize: 4.00 MB
UseCompressedClassPointers: true
CompressedClassSpaceSize: 248.00 MB

Finally, it is worth mentioning that you can disable both UseCompressedClassPointers and UseCompressedOops which should allow the JVM to load as many classes as they fit into memory instead of the limited imposed by CompressedClassSpaceSize virtual memory region.

You can check the default values for your JDK as follows:

$ java -XX:+PrintFlagsFinal -version | grep Compressed

     size_t CompressedClassSpaceSize               = 1073741824                                {product} {default}
     bool UseCompressedClassPointers               = true                                 {lp64_product} {ergonomic}
     bool UseCompressedOops                        = true                                 {lp64_product} {ergonomic}
java version "11.0.4" 2019-07-16 LTS