skip to content

In the HotSpot JVM, what data is stored in the metaspace region, and why does the JVM keep that data in native memory rather than inside the Java heap?

level: juniorimportance: must knowfreq 62%

answer

  1. Klass structures, method bytecode, constant pool, vtables
  2. Native memory, not the heap; grows on demand
  3. Class mirror + statics + interned strings stay on the heap
  4. Freed per class loader, never compacted
  5. -Xmx does not cover it

basics

~20 s

Metaspace holds per-class runtime metadata: type structures, method bytecode, runtime constant pools, field and method descriptors, dispatch tables. It lives in native OS memory, so it grows on demand instead of competing for a fixed slice of the heap.

solid answer

~50 s

Metaspace is the native-memory region where HotSpot stores **class metadata**: the internal type structure of each loaded class, method metadata including the bytecode, the runtime constant pool, field and method descriptors, annotations, and virtual/interface dispatch tables. It is metadata *about* classes, not Java objects. The `java.lang.Class` mirror object, static field values and interned strings all sit on the heap. It is native for two reasons. **Sizing**: metadata volume tracks how many classes an application loads, which is unrelated to object-allocation rate, so carving it out of the heap meant tuning one budget against another. **Growth**: metaspace is committed from the operating system on demand and is unbounded by default, so ordinary applications never hit a metadata ceiling; you opt into a limit with `-XX:MaxMetaspaceSize`. Metadata is never moved or compacted by the object collector. It is allocated from per-class-loader arenas and released in bulk when the owning loader is unloaded.

code

text · 3 lines
text
jcmd <pid> VM.metaspace summary
# Reports used / committed / reserved for class and non-class metaspace,
# plus per-class-loader arena breakdown with 'VM.metaspace basic'

go deeper

for a junior

Name the contents (class structures, method bytecode, constant pool) and the key fact that it is native memory outside the heap that grows on demand.

for a middle

Add the boundary: mirror objects, statics and interned strings on the heap; metadata in metaspace. Mention that -Xmx does not bound it.

for a senior

Add reclamation granularity (per class loader, no compaction) and the operational consequence: cap it explicitly in containers so exhaustion is attributed to the JVM rather than the OS killer.

for a principal

Frame it as a resource-isolation decision: metadata volume scales with class count and deployment topology, not with allocation rate, so it belongs on a separately governed, elastically committed budget.

## What class metadata is Loading a class does far more than remember the bytes of a classfile. The JVM builds native structures that the interpreter and the JIT compiler read on every operation: - a **type structure per class** (HotSpot calls it `InstanceKlass`): superclass link, implemented interfaces, instance-field layout, access flags, initialization state; - **method metadata**: signature, exception table, line-number and local-variable tables, and the **bytecode array itself**; - the **runtime constant pool**: the resolved form of the classfile constant pool, holding symbolic references to other classes, methods and fields plus their resolution state; - **dispatch tables**: the vtable and itable that make a virtual or interface call an indexed jump rather than a search; - profiling counters the JIT uses to decide what to compile. Collectively this is *class metadata*, and the native region holding it is **metaspace**. ## What is deliberately not in metaspace This distinction is the usual follow-up. On the heap you find: the `java.lang.Class` mirror object for each type (it is a normal Java object with a normal object header); the **values of static fields**, which are stored in that mirror; interned `String` instances; and every array or instance your code allocates. Metaspace holds the machine's private description of a type; the heap holds objects that Java code can reference. ## Why native memory Before JDK 8 this metadata lived in the permanent generation, a region *inside* the Java heap with its own fixed maximum. That design had three practical problems. 1. **Two budgets, one knob set.** A container might need a large object heap and few classes, or a modest heap and thousands of classes from many deployed applications. With metadata inside the heap, every deployment had to guess a split in advance. 2. **A fixed ceiling that was reached in normal operation.** The permanent generation was sized once at startup. Applications that generated proxies or redeployed modules would exhaust it even though the machine had free memory. 3. **Awkward collection.** Metadata is not shaped like Java objects: it is not moved, and it becomes garbage only in whole class-loader-sized units. Making a tracing, compacting collector responsible for it added complexity for little benefit. Moving the data into native memory addresses all three. Metaspace is **committed from the OS as classes are loaded** and, in HotSpot, is limited only by available native memory unless you set `-XX:MaxMetaspaceSize`. Growth is elastic: a typical service loads its classes during warm-up, metaspace stabilises, and the knob is never touched. ## How it is reclaimed Metaspace is allocated per class loader: each loader gets its own arena of chunks. Because every piece of metadata belongs to exactly one loader, the JVM can free an entire arena at once when that loader becomes unreachable and its classes are unloaded during a collection cycle. There is no compaction of individual metadata blocks and no per-class free. This is why a class loader that stays reachable keeps *all* of its classes' metadata alive. ## Consequences worth stating in an interview - Metaspace usage is **not visible in a heap dump's object graph as class metadata**; it is native memory, reported separately by the runtime's memory-pool beans and by `jcmd <pid> VM.metaspace`. - Because the default is unbounded, a runaway class generator degrades into native-memory exhaustion of the whole process rather than a bounded, clearly attributed failure. In containers it is common practice to set an explicit `-XX:MaxMetaspaceSize` so the JVM stops itself before the OS kills the container. - `-Xmx` does **not** cover metaspace. A JVM's resident memory is always larger than the maximum heap, and metadata is one of the reasons. ## The short version Metaspace = native storage for the runtime description of loaded classes. Native because its size is driven by class count rather than allocation rate, because it must be able to grow on demand instead of hitting a preconfigured wall, and because its natural reclamation unit is the class loader rather than the individual object.

  • Where are the values of a class's static fields stored, if not in metaspace?
    They are stored in the `java.lang.Class` mirror object, which is an ordinary object on the Java heap. That is why a static field holding a large collection shows up in a heap dump as retained heap under the class mirror, and why static state is collectable only when the defining class loader is unloaded.
  • Does the garbage collector ever touch metaspace?
    Yes, but not as a compacting object collector. Collection cycles perform class unloading: when a class loader is found unreachable, its classes are unloaded and its entire metaspace arena is released. Metadata blocks are never relocated, and individual classes are never freed independently of their loader.

The heap is the warehouse of goods; metaspace is the filing cabinet of blueprints. You need one blueprint per product type no matter how many units you build, so you do not size the cabinet out of the warehouse floor space.

saying these in an interview costs you the question

  • Saying metaspace stores Java objects, or that it is 'part of the heap moved elsewhere'
  • Claiming interned strings or static field values live in metaspace
  • Assuming -Xmx bounds metaspace, so process memory can never exceed the heap maximum
  • Saying metaspace is unlimited so it can never cause a failure
  • Believing individual classes are freed as soon as they are unused, without loader unloading

context