Java virtual machine (two): JVM memory model and OOM

JVM memory model

I believe that some students who have done simple jvm tuning must know a few parameters: -Xms -Xmx -Xmn -Xss -XX:MaxPermSize -XX:MaxMetaspaceSize, then the author will use a picture with these parameters to show Everyone describes the JVM memory model itself and the difference between JDK7 and JDK8.

-Xmn EdenSpace, Survivor1, Survivor2 the sum of the three areas (Young area)

-Xms minimum heap size

-Xmx maximum heap size

-Xss thread private stack size

-XX:MaxPermSize Maximum permanent generation (method area) size

-XX:MaxMetaspaceSize Maximum Metaspace Size

As can be seen from the above figure, both JDK7 and JDK8 have two parts: heap and stack. Among them, there is an extra permanent generation in 7 to store the corresponding data; in 8, the permanent generation in 7 is removed, and the element is redefined. Space to store the corresponding data. (The stack here is not only a thread stack, but also a local method stack)

The above figure shows the corresponding permanent generation in JDK7 and JDK8 and the specific data content stored in the metaspace. In fact, the data stored between the two are similar, but there is one most essential difference between the two, that is, the permanent generation Logically it is part of the heap, but in order to distinguish it from the heap, it is also called "non-heap". Therefore, the method area itself is inside the virtual machine; and the meta space actually exists in the local memory, and its maximum value Also affected by the size of system memory.

Below, we look at a piece of code

public class HelloWorld {
    private static Logger logger = LoggerFactory.getLogger(HelloWorld.class);
    public static void main(String[] args) {
        new Thread(()->{new HelloWorld().sayHello("Hello World!");
            try {
                new CountDownLatch(1).await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
    public void sayHello(String message){
        SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY");
        String today = formatter.format(new Date());
        logger.info(today + ": " + message);
    }
}

And this code is stored in memory as follows

So, why replace the permanent generation with such an implementation as metaspace?

In fact, if you have such a question, you can think about it from your daily development. What problems often encountered when using JDK7 at that time, especially when doing web development, the answer is obvious: java.lang .OutOfMemoryError: PermGen believes that this exception is familiar to everyone. People who have used JDK7 have encountered it, and it is very frequent, but when you change 7 and use 8, although the corresponding, there will be java.lang.OutOfMemoryError :Metaspace, but the probability of this error has been greatly reduced. So this is actually one of the reasons why the permanent generation was removed

Secondly, because JRockit VM does not have the concept of permanent generation, in order to facilitate the integration of Hotspot JVM with it, naturally, there is no need for permanent generation. In addition, according to the official description, in actual development work, it is actually a comparison to optimize the permanent generation. Difficult, unlike heap or stack.

 


 OOM - java.lang.OutOfMemoryError: xxx

I believe that this error will often be encountered in daily development, so the editor here will also give you a detailed introduction to the origin of this error, so that you can have the direction of troubleshooting when you encounter problems.

In fact, as can be seen from the name, OOM is divided into two categories, in-heap OOM and non-heap OOM

In-heap OOM is divided into Java heap space and GC overhead limit; non-heap OOM is also divided into Metaspace and Unable to create new native thread

  • Simply put, Java heap space is that this error will occur when the heap memory reaches the set Xmx or exceeds the available memory of the system when the program is running. However, there are two fundamental reasons for this: increased memory usage , Memory leak

    • The increase in memory usage occurs when the business greatly increases, and the memory demand exceeds business expectations and reaches the value of Xmx

    • Memory leaks are in the heap. Common memory leaks are actually Java object leaks caused by logic code errors.

  • The root cause of GC overhead limit exceeded is when the GC thread spends a lot of time for garbage collection, but it has no effect. This exception occurs at this time, and the default is when the application spends 98% Time to do GC but less than 2% of heap memory is recovered

  • As a very important piece of non-heap memory, Metaspace  is also very inadequate in the performance of OOM. The author combined with some situations encountered in the work, and roughly carried out a simple classification

    • Memory fragmentation Since Metaspace is managed by Chunk List and is being recycled continuously (in the case of Enable ClassUnloading), it will naturally face the problem of memory fragmentation.

    • Frequent loading of js and groovy scripts Since Java allows custom classloaders, when frequently loading js and groovy scripts, the defineClass operation will be triggered continuously. Once the business logic is defective, the metaspace will increase sharply, leading to OOM

    • MethodHandle is the same as above, because when custom classloader or dynamically loading js or groovy scripts, a new MemberName will be generated each time by constructing MethodHandle, which can easily lead to a surge in metaspace

    • Due to improper use of reflection, when the reflection method is called through Method.invoke, the bottom class of the JDK is first implemented through NativeMethodAccessorImpl, but when the number of calls exceeds the value of -Dsun.reflect.inflationThreshold, it will automatically switch to GeneratedMethodAccessorXXX to achieve , And for efficient reflection calls, the JDK will construct a GeneratedMethodAccessorXXX class for each Method reflection call, and each GeneratedMethodAccessorXXX class corresponds to a ClassLoader instance. When in a threaded environment, it is obvious that this phenomenon will be Worse, at this time it is easy to cause the metaspace to reach the threshold and cause OOM

  • Unable to create new native thread  When this error occurs, it has actually been explained that the application has reached the limit of the number of threads it can start

Guess you like

Origin blog.csdn.net/YINZONGCHAO/article/details/106516738