Warm-up

Ask the JVM where its metadata lives

5 minintermediate210 yrs

One concept, guided. Near-impossible to fail.

What this teaches

  • Metaspace is a non-heap pool, outside -Xmx
  • It is unbounded by default, which is the whole change from PermGen
  • There is no PermGen pool on any JDK 8 or later
  • Loading a class costs metadata, and nothing unloads it in a normal run

Starter

Starter.javaOpen in playground
import java.lang.management.*;
import java.util.*;

/**
 * WARM-UP — 5 minutes. One concept. Hard to fail.
 *
 * The JVM will tell you where its class metadata lives. Ask it.
 *
 * TASKS
 *   1. Predict the three booleans before running.
 *   2. Run it.
 *   3. Run it again with a ceiling and watch one of them flip:
 *        java -XX:MaxMetaspaceSize=64m -cp . Starter
 *   4. Try the flag PermGen used to take. The JVM will not start:
 *        java -XX:MaxPermSize=256m -cp . Starter
 *   5. In a comment: which of the numbers printed here would appear in a
 *      heap dump?
 */
public class Starter {
    public static void main(String[] args) {
        boolean permGen = false;
        MemoryPoolMXBean metaspace = null;

        for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
            if (pool.getName().contains("Perm")) permGen = true;
            if (pool.getName().equals("Metaspace")) metaspace = pool;
        }

        System.out.println("a PermGen pool exists        : " + permGen);
        System.out.println("Metaspace is non-heap memory : "
                + (metaspace.getType() == MemoryType.NON_HEAP));
        System.out.println("Metaspace has a ceiling      : "
                + (metaspace.getUsage().getMax() >= 0));

        System.out.println();
        System.out.println("metaspace used : " + metaspace.getUsage().getUsed() / 1024 + " KB");

        ClassLoadingMXBean loading = ManagementFactory.getClassLoadingMXBean();
        System.out.println("classes loaded : " + loading.getLoadedClassCount());
        System.out.println("ever unloaded  : " + loading.getUnloadedClassCount());

        System.out.println();
        System.out.println("every non-heap pool in this JVM:");
        for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
            if (pool.getType() == MemoryType.NON_HEAP) {
                long max = pool.getUsage().getMax();
                System.out.println("  " + pool.getName()
                        + "  max=" + (max < 0 ? "unbounded" : (max / (1024 * 1024)) + " MB"));
            }
        }

        // Question to answer in a comment before you move on:
        // "ever unloaded" is 0 in a program that ran to completion. Is that
        // a bug, and what would have to be true for it to be non-zero?
    }
}

Run it locally:

cd exercises/java/jvm/metaspace-vs-permgen/01-warmup
javac Starter.java -d /tmp/out && java -cp /tmp/out Starter

Done when

  • You predicted each of the three booleans before running
  • You re-ran it with -XX:MaxMetaspaceSize=64m and saw one flip
  • A comment says which of these numbers a heap dump would show

← Back to What replaced PermGen, and why?