Understanding Metaspace Line in Jvm Heap Printout

Understanding metaspace line in JVM heap printout

Metaspace layout

Metaspace consists of one or more Virtual Spaces. Virtual Spaces are areas of contiguous address space obtained from the OS. They are allocated on demand. When allocated, Virtual Space reserves memory from the OS, but not yet commits it. Metaspace reserved memory is the total size of all Virtual Spaces.

Allocation unit inside Virtual Space is Metachunk (or simply Chunk). When a new chunk is allocated from a Virtual Space, the corresponding memory is committed. Metaspace committed memory is the total size of all chunks.

Chunks may differ in size. When a ClassLoader gets garbage collected, all Metachunks belonging to it are freed. Free chunks are maintained in the global free list. Metaspace capacity is the total size of all allocated (i.e. not free) chunks.

New chunk allocation

  1. Look for an existing free chunk in the free list.
  2. If there is no suitable free chunk, allocate a new one from the current Virtual Space.
  3. If the current Virtual Space is exhausted, reserve a new Virtual Space.

Class metadata is allocated within a chunk. Chunk may not contain data from multiple ClassLoaders, but one ClassLoader may have several chunks. Metaspace used is the total size of all class metadata from all chunks.

In jdk 1.8+, how metaspace layout the class info?

First of all, things like Metaspace and String Table are not specified in JLS or JVMS. It's exclusively an internal implementation detail of the particular JVM. For example, there are fully compliant JVM implementations that do not have Metaspace at all.

If we talk about the modern HotSpot JVM, your understanding is not quite correct.

  1. No. An instance of java.lang.String object representing "a" is in Java Heap. The string table contains a reference to that object as long as "a" is strongly reachable.
  2. Yes.
  3. No. Run-Time Constant Pool holds things described in JVMS §4.4. Static fields belong to a class mirror, which is an instance of java.lang.Class in Java Heap.
  4. The same as 1.
  5. Metaspace (as the "meta" prefix suggests) contains the class metadata, but not the data itself. E.g. the metaspace includes the information that the class MetaspaceTest has a field named literalStr of type java.lang.String, but it has nothing to do with the value of that field.
  6. Yes.
  7. No. As written above, Metaspace contains only the description of fields, but not the data. The actual holder of instance fields is an object instance; the actual holder of static fields is a class mirror, i.e. the instance of java.lang.Class in the heap.

Does JVM metaspace always trigger GC when resizing

First of all, "the size of the metaspace" is ambiguous, and thus meaningless without the context. There are at least five metrics: reserved, committed, capacity and used memory as described in this answer, and the high-water mark, also known as capacity_until_gc.

Metaspace layout

Metaspace is not just one contiguous region of memory, so it does not resize in the common sense. Instead, when allocation happens, one or more of the above metrics changes.

  1. On the fastest path a block of metadata is allocated from the current chunk. used memory increases in this case, and that's it.
  2. If there is not enough room in the current chunk, JVM searches for a possibly free existing chunk. If it succeeds in reusing chunks, capacity increases. No GC happens until this point.
  3. If there are no free chunks, JVM tries to commit more memory, unless the new committed size would exceed capacity_until_gc.
  4. If capacity_until_gc threshold is reached, JVM triggers a GC cycle.
  5. If GC does not free enough memory, the high-water mark is increased so that another Virtual Space will be allocated.

After GC, the high-water mark value is adjusted basing on the following JVM flags:

  • -XX:MinMetaspaceFreeRatio (used to calculate how much free space is desirable in the metaspace capacity to decide how much to increase the HWM);
  • -XX:MaxMetaspaceFreeRatio (used to decide how much free space is desirable in the metaspace capacity before decreasing the HWM);
  • -XX:MinMetaspaceExpansion (the minimum expansion of Metaspace in bytes);
  • -XX:MaxMetaspaceExpansion (the maximum expansion of Metaspace without full GC).

TL;DR It's not that simple. JVM can definitely commit more Metaspace memory without triggering GC. However, when HWM is reached, GC is triggered and HWM is recomputed according to the ergonomics policy.

Metaspace utilization of JVM

It shows the current Metaspace occupancy relative to the current Metaspace capacity, i.e.

    used / capacity

Metaspace used, capacity, committed and reserved values are illustrated in this answer.

This is a rather useless metrics since Metaspace can grow and shrink during an application lifecycle.

jstat and jcmd giving different answers for metaspace memory

Good catch! The numbers are indeed different: jstat values can slightly fall behind, since they are updated only after GC, while jcmd values are always current.

So, jcmd GC.heap_info should be more accurate.

Also note that MC in jstat output corresponds to the metaspace committed size, not the capacity.

Metaspace allocated more then MaxMetaspaceSize

The answer is basically here, though not trivial to understand.

The MaxMetaspaceSize limits the committed memory, while your GC logs actually print the reserved memory. So reserved: 1058816K, committed: 9975K, according to your log. Reserved memory does not have to be backed by swap or actual RAM, at all, so usually it is very big.

That is why you see those big numbers in the GC log.



Related Topics



Leave a reply



Submit