Java — OutOfMemoryError: Metaspace from class loading
Fix Metaspace OOM by finding classloader leaks from repeated dynamic class generation or undeployed apps.
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.jarInterpretation
A steadily increasing count of loaded classes with few unloads indicates a classloader leak.
Track metaspace usage
jcmd <pid> VM.metaspaceInterpretation
The report shows committed and used metaspace. Growth without collection points to retained classloaders.
Check for redeploy churn
grep -rn "URLClassLoader\|defineClass\|Proxy.newProxyInstance" srcInterpretation
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