← Debugging Guides

阅读中文版本

Java — OutOfMemoryError: Metaspace from class loading

Fix Metaspace OOM by finding classloader leaks from repeated dynamic class generation or undeployed apps.

advanceddebuggingjavajvm

Symptoms

  • java.lang.OutOfMemoryError: Metaspace
  • The heap is fine but the process grows over hours or days
  • The error appears after repeated redeploys or dynamic proxies
  • Class count keeps increasing under load

Possible causes

  • A classloader retains references so loaded classes are never unloaded
  • Frameworks generate classes at runtime without bounds
  • Applications are reloaded in the same JVM without releasing old classloaders
  • Metaspace is capped too low for the number of loaded classes

Diagnosis steps

Watch class loading

java -Xlog:class+load=info -jar app.jar

Interpretation

A steadily increasing count of loaded classes with few unloads indicates a classloader leak.

Track metaspace usage

jcmd <pid> VM.metaspace

Interpretation

The report shows committed and used metaspace. Growth without collection points to retained classloaders.

Check for redeploy churn

grep -rn "URLClassLoader\|defineClass\|Proxy.newProxyInstance" src

Interpretation

Dynamic proxies and generated classes allocate metaspace that only frees when their classloader becomes unreachable.

Root cause

Metaspace filled because classes and their classloaders were retained, typically from repeated dynamic class generation or redeploys in one JVM, so loaded classes were never unloaded.

Fix

Bound dynamic class generation, release or reuse classloaders on redeploy, and cache generated proxies instead of recreating them. Set a Metaspace limit that fits legitimate class counts and monitor growth.

Verify the fix

Rerun and confirm loaded class count stabilizes and Metaspace usage plateaus, and confirm the OutOfMemoryError does not recur.

Symptom walkthrough

The JVM fails with OutOfMemoryError: Metaspace while heap usage stays normal. Metaspace holds class metadata, so the growth comes from classes being loaded and never unloaded. This often follows repeated application redeploys in one JVM, or frameworks that generate classes at runtime, such as proxy and expression libraries, where each generation consumes metaspace that is only reclaimed when its classloader becomes unreachable.

Fix in practice

Bound or cache runtime-generated classes, ensure classloaders are released on redeploy, and avoid unbounded dynamic proxy creation. Cap Metaspace to something that fits legitimate class counts, but first confirm the growth is a leak rather than simply a large application.

Verification

Rerun and confirm the loaded class count stabilizes and Metaspace usage plateaus, then confirm the error does not recur. A flattening class count under sustained load proves the leak is gone.

Diagnostic commands

Check the behavior with commands like these:

java -Xlog:class+load=info -jar app.jar
jcmd <pid> VM.metaspace
grep -rn "URLClassLoader\|defineClass\|Proxy.newProxyInstance" src