Java8: PermGen and Metaspace

一, PermGen (permanent generation)

Most Java programmers should have seen the exception "java.lang.OutOfMemoryError: PermGen space" . The “PermGen space” here refers to the method area. However, the method area and "PermGen space" are essentially different. The former is the specification of the JVM, while the latter is an implementation of the JVM specification, and only HotSpot has "PermGen space", while for other types of virtual machines, such as JRockit (Oracle), J9 (IBM) does not have "PermGen space" ". Because the method area mainly stores related information of the class, it is easier for the dynamically generated class to appear in the permanent memory overflow. The most typical scenario is that in the case of more jsp pages, it is prone to permanent Generation memory overflow. We now simulate the memory overflow of "PermGen space" by dynamically generating classes:

package com.paddx.test.memory;
 
public class Test {
}
package com.paddx.test.memory;
 
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
 
public class PermGenOomMock{
    public static void main(String[] args) {
        URL url = null;
        List<ClassLoader> classLoaderList = new ArrayList<ClassLoader>();
        try {
            url = new File("/tmp").toURI().toURL();
            URL[] urls = {url};
            while (true){
                ClassLoader loader = new URLClassLoader(urls);
                classLoaderList.add(loader);
                loader.loadClass("com.paddx.test.memory.Test");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

The results are as follows:

 

The JDK version used in this example is 1.7, and the specified PermGen area is 8M. By loading the Test class each time a different URLClassLoader object is generated, a different class object is generated, so that we can see the familiar "java.lang.OutOfMemoryError: PermGen space" exception. The reason why JDK 1.7 is used here is because In JDK 1.8, HotSpot has no "PermGen space" interval, instead it is a thing called Metaspace. Let's take a look at the difference between Metaspace and PermGen space.

二, Metaspace (元空间)

In fact, the work of removing the permanent generation started from JDK1.7. In JDK1.7, some of the data stored in the permanent generation has been transferred to Java Heap or Native Heap. However, the permanent generation still exists in JDK1.7 and has not been completely removed. For example, Symbols has been transferred to the native heap; the interned strings have been transferred to the java heap; the static variables of the class have been transferred to java. Heap. We can compare the difference between JDK 1.6 and JDK 1.7 and JDK 1.8 through a program. Take string constants as an example:

package com.paddx.test.memory;
 
import java.util.ArrayList;
import java.util.List;
 
public class StringOomMock {
    static String  base = "string";
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i=0;i< Integer.MAX_VALUE;i++){
            String str = base + base;
            base = str;
            list.add(str.intern());
        }
    }
}

This program continuously generates new strings, which can consume memory more quickly. We run through JDK 1.6, JDK 1.7 and JDK 1.8 respectively:

JDK 1.6 Run results:

JDK 1.7 Run results:

JDK 1.8 Run results:

From the above results It can be seen that under JDK 1.6, there is a memory overflow of "PermGen Space", and in JDK 1.7 and JDK 1.8, heap memory overflow occurs, and PermSize and MaxPermGen in JDK 1.8 are invalid. Therefore, you can roughly verify that JDK 1.7 and 1.8 transfer string constants from the permanent generation to the heap, and there is no permanent generation conclusion in JDK 1.8. Now let's see what the meta space is.

       The essence of the metaspace is similar to the permanent generation, and is an implementation of the method area in the JVM specification. But the biggest difference between meta-space and permanent generation is that meta-space is not in the virtual machine, but uses local memory. Therefore, by default, the size of the metaspace is limited only by the local memory limit , but the size of the metaspace can be specified by the following parameters:

-XX:MetaspaceSize, the initial space size, which will trigger garbage collection for type unloading, and the GC will adjust the value: If you release a lot of space, reduce the value appropriately; if you release a small amount of space, increase the value appropriately when MaxMetaspaceSize is not exceeded.

-XX:MaxMetaspaceSize, the maximum space, the default is no limit.

In addition to the above two options of the specified size, there are two other GC-related properties: -XX:MinMetaspaceFreeRatio, after GC, the minimum percentage of Metaspace remaining space capacity, reduced to garbage collection caused by 分配 -XX:MaxMetaspaceFreeRatio, after the GC, the maximum percentage of the remaining space capacity of the Metaspace is reduced to releaseSpace collection caused by garbage collection

now we are Rerun code snippet 4 under JDK 8, but this time no longer specify PermSize and MaxPermSize. Instead, specify the size of MetaSpaceSize and MaxMetaSpaceSize. The output is as follows:

From the output result, we can see that this time there is no permanent overflow, but the overflow of the meta space.

三, Summary

Through the above analysis, we should be clear about the conversion of the permanent meta-metaspace in JDK 8. But everyone should have a question, why is this conversion? So, finally, I would like to summarize the following reasons:

1, the string exists in the permanent generation, prone to performance problems and memory overflow.

2, class and method information is difficult to determine its size, so it is difficult to specify the size of the permanent generation, too small is prone to permanent generation overflow.

3, permanent generation brings unnecessary complexity to the GC, and the recycling efficiency is low.

4, Oracle may combine HotSpot and JRockit into one.