Wouldn't there be OOM using Metaspace in Java 8?

Keywords: Java simulator jvm

Foreword: In Java 8, the emergence of Metaspace prevents us from encountering the problem of java.lang.OutOfMemoryError: PermGen, but we should remember that this new feature will not eliminate the memory leak caused by class loading.

(1) A brief introduction to Metaspace
(1) Memory model: Most class metadata are allocated in local memory, and the "klasses" used to describe class metadata have been removed.
(2) Capacity: By default, it is limited only by local memory, but we can limit it.

(2) Next, see if there will be OOM in Metaspace.
We can use dynamic proxy to generate a large number of proxy class information to fill the metadata area. The code is as follows

public interface MetaspaceFacade {
    void method(String input);
}
public class MetaspaceFacadeImpl implements MetaspaceFacade {

    public void method(String name) {
    }
}
public class MetaspaceFacadeInvocationHandler implements InvocationHandler {

    private Object classAImpl;

    public MetaspaceFacadeInvocationHandler(Object impl) {
       this.classAImpl = impl;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

       return method.invoke(classAImpl, args);
    }
}
public class ClassMetadataLeakSimulator {

    private static Map<String, MetaspaceFacade> classLeakingMap = new HashMap<String, MetaspaceFacade>();
    private final static int NB_ITERATIONS_DEFAULT = 50000;

    /**
     * @param args
     */
    public static void main(String[] args) {

        System.out.println("Class metadata leak simulator");

        int nbIterations = NB_ITERATIONS_DEFAULT;

        try {

            for (int i = 0; i < nbIterations; i++) {

                String fictiousClassloaderJAR = "file:" + i + ".jar";

                URL[] fictiousClassloaderURL = new URL[] { new URL(fictiousClassloaderJAR) };

                URLClassLoader newClassLoader = new URLClassLoader(fictiousClassloaderURL);

                MetaspaceFacade t = (MetaspaceFacade) Proxy.newProxyInstance(newClassLoader,
                        new Class<?>[] { MetaspaceFacade.class },
                        new MetaspaceFacadeInvocationHandler(new MetaspaceFacadeImpl()));

                classLeakingMap.put(fictiousClassloaderJAR, t);
            }
        } 
        catch (Throwable any) {
            System.out.println("ERROR: " + any);
        }

        System.out.println("Done!");
    }
}

1. First, without any settings (heap size needs to be guaranteed), run to get the following screenshot

As you can see, Metaspace has been dynamically expanded, with over 300 M of local memory, and no OOM events have occurred since more than 50,000 classes were loaded. Next, let's limit it.

2. The parameters of the virtual machine are as follows: -Xmx2g-Xms2g-Xmn1g-XX:+PrintGCDetails-XX:MaxMetaspaceSize=128m, run to get the following screenshot

As you can see, when Metaspace is exhausted, OOM events will be thrown. Note the difference between MaxPermSize. MaxMetaspaceSize does not allocate such a large memory at jvm startup, but MaxPermSize allocates such a large memory.

So the question is, if we don't set up MaxMetaspaceSize, can we use all the memory of the system?
metaspace is probably OS Kill because it's used endlessly, so it's usually better to set it up.

Posted by ow-phil on Thu, 13 Jun 2019 16:30:21 -0700