The Java Virtual Machine…

  • Deep understanding of the Java VIRTUAL machine -Java memory area thorough analysis
  • In-depth understanding of Java Virtual Machine – common VM parameter analysis
  • Understand the principles of the Java Virtual Machine-JVM memory allocation and reclamation strategy, so that you can never be illiterate about JVM memory allocation
  • Understanding the Java VIRTUAL Machine – How to use the JDK’s own command-line tools to monitor the performance of millions of highly concurrent virtual machines
  • In-depth understanding of the Java Virtual Machine – How to leverage VisualVM for performance analysis of highly concurrent projects
  • Deep Understanding of Java Virtual Machines – Do you understand GC algorithms

This article mainly introduces the Java memory area, but also some of the most basic knowledge as Java virtual machine, after understanding these knowledge, can better conduct Jvm tuning or more in-depth learning, originally these knowledge is obscure, so I hope to be able to explain the thorough and image.

0 runtime data area

As the JVM executes Java programs, it divides the memory it manages into several different data regions.

The memory managed by Java virtual machines is divided into Method Area, VM Stack, Native Method Stack, Heap, and Program Counter Register five areas.

Each of these regions has its own purpose and time of creation and destruction. Some regions exist with the start of a virtual machine process, while others are created and destroyed depending on the start and end of a user thread. The details are shown in the figure below:

The figure above illustrates the JDK1.8 JVM runtime memory data partitioning. The biggest difference between 1.8 and 1.7 is that metadata sections replace permanent generations. Similar in nature to permanent generations, meta-spaces are implementations of method areas in the JVM specification. However, the biggest difference between a meta-space and a persistent generation is that the metadata space is not in the virtual machine, but uses local memory.

1 Program Counter Register

The Program Counter Register is a small memory space that can be thought of as a line number indicator of the bytecode being executed by the current thread. In the conceptual model of virtual machine, the bytecode interpreter works by changing the value of the counter to select the next bytecode instruction to be executed, and basic functions such as branch, loop, jump, exception handling and thread recovery depend on this counter.

A program counter is a piece of “thread-private” memory, where each thread has a separate program counter that can restore the switched thread to its correct execution position.

  • This is a Java method

The counter records the address of the virtual machine bytecode instruction being executed.

  • Native methods are implemented

The counter is empty (Undefined), because the Native method is Java directly calls the local C/C++ library through JNI. It can be considered that the native method is equivalent to an interface exposed to Java by C/C++, and Java calls C/C++ methods by calling this interface. Since this method is implemented in C/C++ rather than Java. The bytecode is naturally not generated, and the memory allocation for C/C++ execution is determined by the language itself, not by the JVM.

  • The program counter is also the only memory area that does not have any OutOfMemoryError cases specified in the Java Virtual Machine specification.

In fact, I feel that this area, as our developers can not interfere too much, we just need to understand the existence of this area, and there is no corresponding parameters of virtual machine can be set and control.

2 Java Virtual Machine Stacks

The Java Virtual Machine Stack describes the memory model for Java method execution: When each method is executed, a Stack Frame will be created. As can be seen from the figure above, the Stack Frame stores information such as local variable table, operand Stack, dynamic link, method exit and so on. The process of each method from invocation to completion of execution will correspond to the process of a stack frame in the virtual machine stack and out of the stack.

Like program counters, the Java virtual machine stack is thread private.

The table of local variables contains all kinds known at compile time:

  • Basic data types (Boolen, Byte, CHAR, short, int, float, Long, double)
  • Object reference (reference type, which is not equal to the object itself and may be a pointer to the object’s starting address, a handle representing the object, or some other location associated with the object)
  • The returnAddress type (refers to the address of a bytecode instruction)

64-bit long and double data occupy two local variable slots, and the rest occupy only one. The memory space required for the local variable table is allocated at compile time. When entering a method, how much local variable space the method needs to allocate in the frame is completely determined, and the size of the local variable table does not change during the method run.

The Java Virtual Machine specification specifies two exceptions for this area:

  • StackOverflowError: A thread request with a stack depth greater than the virtual machine allows will throw this exception.
  • OutOfMemoryError: This exception is thrown when a dynamically scalable virtual stack cannot allocate sufficient memory during expansion.

JVM parameters are used to control the memory size of the stack to simulate StackOverflowError.

3 Native Method Stack

The Native Method Stack is similar to the Java virtual machine Stack. The difference is that the VIRTUAL machine Stack performs Java methods (that is, bytecode) services for the VIRTUAL machine, while the Native Method Stack serves the Native methods used by the virtual machine.

The language, methods, and data structures used in the local method stack are not mandated in the virtual machine specification, so specific virtual machines can implement it. There are even virtual machines (Sun HotSpot virtual machines) that simply combine the local method stack with the virtual machine stack. As with virtual machines, the local method stack throws StackOverflowError and OutOfMemoryError exceptions.

  • Use the -xSS parameter to reduce stack memory size (see this article for more JVM parameters: In-depth Understanding of Java Virtual Machine – Common VM Parameter Analysis)

In this example, we set the stack memory size to 256K (1M by default) and define a variable to see how deep the stack recursion is.

/ * * *@ClassName Test_02
 * @DescriptionSet Jvm parameters: -xss256K *@AuthorOuyang Sihai *@Date2019/9/30 his *@Version1.0 * * /
public class Test_02 {

    private int len = 1;

    public void stackTest(a) {
        len++;
        System.out.println("stack len:" + len);
        stackTest();
    }

    public static void main(String[] args) {
        Test_02 test = new Test_02();
        try {
            test.stackTest();
        } catch(Throwable e) { e.printStackTrace(); }}}Copy the code

Set JVM parameters at runtime

Output result:

4 Java Heap

For most applications, the Java Heap is the largest chunk of memory managed by the Java VIRTUAL machine, which is shared by all threads and created when the virtual machine is started. The only purpose of this memory area is to hold object instances. Almost all object instances are allocated memory here, and the size of each allocation is variable. Allocated in the Heap memory to store the object instance, in fact only save object instance attribute value, attribute types and the type of the object itself tag, etc., do not save the object’s methods (methods are instructions and stored in the Stack), allocate some memory in the Heap stored object instance and object serialization is similar.

The Java Heap is the primary area managed by the Garbage collector and is therefore also known as the “Garbage Collected Heap.” From the perspective of memory reclamation, the memory space can be divided as follows:

  • New generation (Young) : new generation of objects stored in the new generation of priority, the new generation of objects die overnight, the survival rate is very low. In the new generation, the conventional application of a garbage collection can generally recover 70% to 95% of the space, recycling efficiency is very high.

If the new generation can be further divided into Eden space, From Survivor space and To Survivor space, the default ratio is 8:1:1.

  • Tenured: Objects that have survived multiple GC cycles in the New generation will enter the Old age. The life cycle of objects in the old age is longer, the survival rate is higher, the frequency of GC in the old age is relatively low, and the recovery speed is slower.
  • Permanent generation (Perm) : Permanent generation stores data such as class information, constants, static variables, code compiled by the just-in-time compiler, etc. For this area, the Java Virtual Machine specification states that garbage collection can be eliminated, and in general, garbage collection is not performed.

The new generation and the old generation make up the entire memory area of the Java heap, while the permanent generation, which is not part of the heap space, was used as a method area implementation by the Sun HotSpot VIRTUAL machine prior to JDK 1.8

In addition, the general picture of heap space memory allocation is highlighted again, which will be helpful for some Jvm optimization tips.

  • The old days: two-thirds of the heap space
  • Young generation: one-third of the heap space Eden Area: 8/10 of the young generation space SURVIVOR0:1/10 of the young generation space Survivor1:1/10 of the young generation space

Finally, let’s use a simple example to visualize a heap overflow.

  • JVM parameter Settings: -xMS10m -XMx10m

Both the minimum and maximum heap values are set to 10m. If you don’t know what these parameters mean, you can refer to this article: Understanding Java Virtual Machine-Common VM Parameter Analysis in Depth

/ * * * Args VM: - Xms10m - Xmx10m - XX: + HeapDumpOnOutOfMemoryError *@author zzm
 */
public class HeapTest {

    static class HeapObject {}public static void main(String[] args) {
        List<HeapObject> list = new ArrayList<HeapObject>();

        // Keep adding objects to the heap
        while (true) {
            list.add(newHeapObject()); }}}Copy the code

Output result:

Figure in the Java. Lang. OutOfMemoryError, and prompt the Java heap space, this means that the Java heap memory leak is the case.

Dump file analysis of the heap

I used the VisualVM tool for analysis, and read this article on how to use this tool (In-depth Understanding of the Java Virtual Machine – How to use VisualVM for performance analysis of high concurrency projects). After running the program, the VisualVM tool opens at the same time to see how heap memory has changed.

In the figure above, you can see that the maximum heap size is 30m, but the size of the heap being used is approaching 30m, so it is easy to run out of heap memory.

Then look at the dump file.

As shown in the figure above, most of the objects in the heap are HeapObjects, so it is because this object is generated all the time that the heap memory is not allocated enough, so the memory overflow occurs.

Let’s look at GC.

As shown in the figure above, Eden’s new generation has a total of 48 minor GC, which takes 1.168s, basically meeting the requirements, but survivor does not, which is abnormal. Meanwhile, Old Gen’s Old generation has a total of 27 full GC, which takes 4.266s, which takes a long time and has more GC. This is due to a large number of large objects moving into the old age, so full GC is frequent.

5 Method Area

The Method Area, like the Java heap, is an Area of memory shared by individual threads. It is used to store a cup of virtual machine-loaded class information, constants, static variables, timely compiler compiled code, and so on. Because the data stored in a method area has a kind ratio to the Heap, it is also called non-heap.

Runtime Constant Pool

The Runtime Constant Pool is part of the method area. The Constant Pool Table is used to store various literals and symbolic references generated at compile time. This part of the Constant Table is stored in the runtime Constant Pool of the method area after the Class is loaded.

The Java virtual machine has strict rules on the format of each part of the Class file (including the constant pool, of course), and each byte used to store what kind of data must meet the specification before the virtual machine accepts, loads, and executes it. The Java Virtual Machine specification does not specify any details about runtime constant pools, however, and virtual machines implemented by different vendors can implement this memory area as they see fit. In general, however, in addition to saving descriptor references in Class files, translated direct references are also stored in the runtime constant pool.

Runtime constant pool relative to the Class file another important feature of the constant pool is dynamic, the Java language does not require constant must only compiler to produce, is not in the content of the constant pool can enter method in the Class files of runtime constant pool area, runtime might also put new constants in pool.

Run-time constant pool example

One of the more dynamic types used in development is the String intern() method. So, we use the intern() method as an example to illustrate the runtime constant pool.

String. Intern () is a native method that returns the String in the String constant pool if it already contains a String equal to the String. Otherwise, join the pool and return.

/ * * *@ClassName MethodTest
 * @DescriptionVm parameter Settings: -Xms512m -Xmx512m -Xmn128m -XX:PermSize=10M -XX:MaxPermSize=10M -XX:NewRatio=4 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:-HeapDumpOnOutOfMemoryError -XX:+UseParNewGC -XX:+UseConcMarkSweepGC *@AuthorOuyang Sihai *@Date 2019/11/25 20:06
 * @Version1.0 * * /

public class MethodTest {

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        long i = 0;
        while (i < 1000000000) { System.out.println(i); list.add(String.valueOf(i++).intern()); }}}Copy the code

Vm parameters:

-Xms512m -Xmx512m -Xmn128m -XX:PermSize=10M -XX:MaxPermSize=10M -XX:NewRatio=4 -XX:SurvivorRatio=8 – XX: MaxTenuringThreshold = 15 – XX: – HeapDumpOnOutOfMemoryError – XX: XX: + UseParNewGC – + UseConcMarkSweepGC began to heap memory and maximum heap memory is 512 m, The size of permanent generation is 10m, the new generation and the old generation are 1:4, E:S1:S2=8:1:1. The garbage collector used is ParNew of the new generation and CMS of the old generation.

After going through this setup, see the results:

First the heap runs out of memory and then we’ll see how GC is doing. After setting these parameters, GC should be fine, wait and see.

In the previous section, we can see that the JVM performed well when performing 21 minor GC sessions in 1.179 seconds (less than 50ms on average) and 117 full GC sessions in 45.308s (less than 1s on average).

-xx :PermSize=10M -XX:MaxPermSize=10M -XX:MaxPermSize=10M Java. Lang. OutOfMemoryError: PermGen space, this suggests that the constant pool overflow; In JDK1.7 and later, this will continue without error. As mentioned earlier, the permanent generation has been removed.

6 Direct Memory

Direct Memory is not part of the run-time data region of the virtual machine, nor is it defined in the Java Virtual Machine specification. However, this portion of memory is also frequently used, which can cause OutofMemoryErrors.

In NIO, in order to speed up IO operations, we use a direct memory approach, which is much faster than traditional IO.

NIO introduces a Channel and Buffer based I/O approach, which can use Native libraries to allocate out-of-heap memory directly, and then operate as a reference to this memory through a DirectByteBuffer object stored in the Java heap. This avoids copying data back and forth between the Java heap and Native heap, which can significantly improve performance in some scenarios.

When configuring VM parameters, the system sets parameters such as -xmx based on the actual memory. However, the direct memory is often ignored. As a result, the sum of all memory regions exceeds the physical memory limit (including the physical and operating system limits), and an OutOfMemoryError occurs during dynamic expansion.

Original is not easy, old iron, the article needs your praise to let more people see, I hope to help you!

2, the article has improper, welcome to correct, if you like wechat reading, you can also pay attention to my wechat public number: learn Java, public number has 6W fans, reply: 1024, access to the public number of gift package, public number long-term release Java quality series of articles, pay attention to us will let you harvest a lot!