This is the fourth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

📑 Soon to learn

JVM memory management of the relevant knowledge, the JVM memory management for what specifications

Java from compile to execute

The.class file is loaded by a ClassLoader into the method area and executed by the JVM execution engine to translate the bytecode into machine code

Explain execution and JIT execution

Explain to perform

The JVM is written in C++ and needs to be interpreted by a C++ interpreter

Explain the pros and cons of implementation

Interpretation through the JVM is relatively slow

JIT (Just-in-Time Compilation)(Hotspot)

Method, a code loop to a certain number of times back end more than 10,000 code will go hotspot compilation JIT execution (hotspot) (JIT) Java code directly translated into (without the interpreter) assembly code machine code

Advantages and disadvantages of JIT execution

It is fast but takes time to compile

The JVM is a specification

Both JVM features are cross-platform language independent

  • cross-platform
    • The same code will perform the same on different platforms
  • JVM language independence
    • Only.class files can be recognized by the JVM as long as the relevant language files are compiled into.class files
      • The Java language, such as Groove, Kotlin, and so on, is essentially language-independent, so as long as it conforms to the JVM specification, it is possible to execute a language-level compilation of.java.kt files into.class files

So the JVM is a specification

JVM memory management specification

Runtime data area

During the execution of Java programs, the Java VIRTUAL Machine divides the memory managed by it into several different data regionsAnd the data partition is the basisThread private å’Œ Threads shareI’m going to divide these two

  • Thread shared area
    • The thread shared area is divided into the method area and the heap
  • Method area (permanent generation (before JDk1.7) metadata (JDK1.8) called hotspot implementation)
    • In the JVM specification, this is referred to as the method area
      • justhotSpot VM This product is used a lot.hotSpotUse of permanent generation or meta-space implementation method area Hotspot different versions of the implementation

Almost everything in the heap is allocated here

Thread private area An area divided for each thread started

Direct memory Out-of-heap memory

  • The JVM virtualizes the managed areas at runtime

By JVM memory management, objects can be put into the heap, and when using, only need to find the reference of the object can be used directly, rather than directly through the allocation of memory, address addressing to calculate the offset, offset length more convenient.

  • This data is not virtualized (8GB of memory outside the runtime JVM takes 5G of memory outside the heap and 3G).

It can be applied, used and released in a certain way. But more troublesome, involving the allocation of memory, address allocation and so on

Java method running with the virtual machine stack

The virtual machine stack

The stack structure stores the data, instructions, and return addresses that the current thread needs to run Java methods.

public static void main(String[] args) {
    A();
}

private static void A(a) {
    B();
}

private static void B(a) {
    C();
}

private static void C(a) {}Copy the code

For example, when we run the main method, we start a thread, at which point the JVM creates a virtual machine stack in the runtime data area. Every time a method is run, a stack frame is pushed

  • Vm stack size limit Xss parameter specifies

-Xsssize Sets the thread stack size in bytes. K or K indicates KB, M or M indicates MB, and G or G indicates GB. The default value depends on virtual memory. The following example sets the ThreadStackSize to 1024kb in different units: -xss1m-xss1024k -xss1048576 this option is equivalent to -xx :ThreadStackSize.Copy the code

The stack frame

The stack frame mainly contains

  • Local variable scale
  • The operand stack
  • Dynamic connection
  • To complete the export

The effect of stack frames on memory areas

Take the following code as an example

public class Apple {
    public int grow(a) throws Exception {
        int x = 1;
        int y = 2;
        int z = (x + y) * 10;
        return z;
    }
    public static void main(String[] args) throws Exception {
        Apple apple = newApple(); apple.grow(); apple.hashCode(); }}Copy the code

Because the JVM recognizes.class files, not.java files. Therefore, we need to get its bytecode, which can be obtained by right-clicking the ASM Plugin or by javap -v xxx.class (this article is obtained by javap). The bytecode is as follows

Classfile /XXX/build/classes/java/mainXXX/Apple.class Last modified 2021-8-11; size 668 bytes MD5 checksum d10da1235fad7eba906f5455db2c5d8b Compiled from "Apple.java" public class Apple minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#29 // java/lang/Object."<init>":()V #2 = Class #30 // Apple #3 = Methodref #2.#29 // Apple."<init>":()V #4 = Methodref #2.#31 // Apple.grow:()I #5 = Methodref #6.#32 // java/lang/Object.hashCode:()I #6 = Class #33 // java/lang/Object #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Apple; #14 = Utf8 grow #15 = Utf8 ()I #16 = Utf8 x #17 = Utf8 I #18 = Utf8 y #19 = Utf8 z #20 = Utf8 Exceptions #21 = Class #34  // java/lang/Exception #22 = Utf8 main #23 = Utf8 ([Ljava/lang/String;)V #24 = Utf8 args #25 = Utf8 [Ljava/lang/String;  #26 = Utf8 apple #27 = Utf8 SourceFile #28 = Utf8 Apple.java #29 = NameAndType #7:#8 // "<init>":()V #30 = Utf8 Apple #31 = NameAndType #14:#15 // grow:()I #32 = NameAndType #35:#15 // hashCode:()I #33 = Utf8 java/lang/Object #34 = Utf8 java/lang/Exception #35 = Utf8 hashCode { public Apple(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Apple; public int grow() throws java.lang.Exception; descriptor: ()I flags: ACC_PUBLIC Code: stack=2, locals=4, args_size=1 0: iconst_1 1: istore_1 2: iconst_2 3: istore_2 4: iload_1 5: iload_2 6: iadd 7: bipush 10 9: imul 10: istore_3 11: iload_3 12: ireturn LineNumberTable: line 5: 0 line 6: 2 line 7: 4 line 8: 11 LocalVariableTable: Start Length Slot Name Signature 0 13 0 this Apple; 2 11 1 x I 4 9 2 y I 11 2 3 z I Exceptions: throws java.lang.Exception public static void main(java.lang.String[]) throws java.lang.Exception; descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #2 // class Apple 3: dup 4: invokespecial #3 // Method "<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #4 // Method grow:()I 12: pop 13: aload_1 14: invokevirtual #5 // Method java/lang/Object.hashCode:()I 17: pop 18: return LineNumberTable: line 11: 0 line 12: 8 line 13: 13 line 14: 18 LocalVariableTable: Start Length Slot Name Signature 0 19 0 args [Ljava/lang/String; 8 11 1 apple Lcom/enjoy/ann/Apple; Exceptions: throws java.lang.Exception } SourceFile: "Apple.java"Copy the code

From the bytecode we can see this

  public Apple();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Apple;
Copy the code

This is the Apple constructor, although we didn’t write it, but the default is no-parameter constructor implementation

Back at the bottom of the body we parse the grow() method

 public int grow() throws java.lang.Exception;
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: iconst_1
         1: istore_1
         2: iconst_2
         3: istore_2
         4: iload_1
         5: iload_2
         6: iadd
         7: bipush        10
         9: imul
        10: istore_3
        11: iload_3
        12: ireturn
      LineNumberTable:
        line 5: 0
        line 6: 2
        line 7: 4
        line 8: 11
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  this   Apple;
            2      11     1     x   I
            4       9     2     y   I
           11       2     3     z   I
    Exceptions:
      throws java.lang.Exception
Copy the code

So we can see that the code area is 0, 1, 2, 3

This is the table of bytecode addresses (relative to the offset of the method) in the grow stack frame. When the program runs, The number in the program counter is swapped for the line number 0, 1, 2, 3 [bytecode line number] of the bytecode from which the method is run. The bytecode line number corresponds to the JVM bytecode instruction mnemonic which is understood below in the bytecode address table

         0: iconst_1
         1: istore_1
         2: iconst_2
         3: istore_2
         4: iload_1
         5: iload_2
         6: iadd
         7: bipush        10
         9: imul
        10: istore_3
        11: iload_3
        12: ireturn
Copy the code

First, enter the grow method and record the line number in main () as the completion exit. For example, the grow method in main has the bytecode address of 3. After the method completes, the next line of bytecode address of the completion exit is executed

Enter the grow() stack frame. The program counter sets the counter to 0. If the class is a static method, the local variable table is unchanged. If the class is not a static method, the object instance this is added to the local variable quantity. Like the image below

  • 0: iconst_1
    • I = int const; I = int const; I = int const;

The code code then runs the next line

  • 1: istore_1
    • Let’s change the program counter count to 1, and then I means int, store means store, and 1 means store the subscript in the local variable table at the position of 1, so we’re going to store the int with the operand of 1 off the stack in the local variable.

The above two bytecodes correspond to int X = 1

I_const_1 corresponds to the definition 1 on the right, and i_store_1 corresponds to the variable X which stores 1, int y = 2

Int z = (x + y) * 10; X and y are stored in the local layout variable, so when we execute this code, we don’t need to do the above steps. We can use 4: iload_1 to load the data in position 1 of the layout variable into the operand stack

Next, execute 6: iadd in code to pop up two operands from the operand stack and save the result to the top of the stack. At this time, the result will only remain in the operand stack

By this time we have finished(X + y)This step, let’s see* 10This step, this is where we jump 7: bipush 10This value is also a constant value, but is a little different for larger operations. 0-5 is const, and the other values are used by the JVMbipushThe instruction pushes the constant onto the stack. 10 corresponds to the value to be pushed in.

Then we skip to line 9: imul. This is an addition operation instruction. We can see that the operation number goes directly from 7 to 9.This is because the bipush instruction is too large, occupying two operation instruction lengths.

At this point, we have the result of the calculation, and we need to assign it to the local variable z for variable storage.

At this point, we’re donez = (x + y) * 10The operation of the. The last line is executedreturn z;First, take z, load it into the operand stack, and then use iReturn to return the result. The method ends. At this point,To complete the exportThe value of the program counter stored in the previous method, returning to the correct location in the previous method.

supplement

0 1 2 3 4 7 9 Bytecode offset for this method

The program counter only stores its own value for this method. Dynamic concatenation ensures that multiple threads execute the program correctly

Local method stack

Native Method Stacks play a very similar role to the virtual machine stack except that the virtual machine stack performs Java methods (that is, bytecode) services for the JVM, and the Native Method stack serves Native methods used by the JVM. In hotSpot, the local method stack is integrated with the virtual machine stack

In the local method stack, the program counter is null because the form running in the local method stack is not bytecode


Thread shared area

So let’s do a little bit of code

public class Learn {
    static int NUMBER = 18; // Static variables are basic data types
    static final int SEX = 1; // Constant basic data type
    static final Learn LERARN = new Learn(); // Member variables point to objects
    private boolean isYou = true; // Member variables


    public static void main(String[] args) {
        int x = 18;// Local variables
        long y = 1;
        Learn learn = new Learn(); // Local variable objects
        learn.isYou = false;// Local variables change values
        learn.hashCode(); // Local variables call native methods
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(128 * 1024 * 1024);// Allocate 128M of direct memory}}Copy the code

Class loading process

The Learn is loaded into the method area

Static variables and constants in the class are loaded into the method area.

Methods area

Is an area of runtime memory that can be shared by threads. It stores structural information for each class,

The heap

Almost all of the objects that we apply for are stored here. We often say garbage collection, the operation of the object is the heap. As objects are created frequently, more and more heap space is taken up, and objects that are no longer used need to be reclaimed from time to time. This, in Java, is called Garbage Collection.

When you create, do you allocate on the heap or on the stack?

This has to do with two things:objectAnd in theThe location in the Java class. For normal objects, the JVM first creates the object on the heap and then uses its references elsewhere. For example, save this reference in the local variable table of the virtual machine stack. For basic data types (byte, short, int, long, float, double, char), there are two cases. When you declare an object of a basic data type in the body of a method, it is allocated directly on the stack. Otherwise, it’s allocated on the heap.

JVM memory processing

Let’s start with a piece of code for subsequent analysis

public class JVMObject {
    public final static String MAN_TYPE = "man"; / / constant
    public static String WOMAN_TYPE = "woman";  // Static variables
    public static void  main(String[] args)throws Exception {
        Teacher T1 = new Teacher();
        T1.setName("A");
        T1.setSexType(MAN_TYPE);
        T1.setAge(36);
        for(int i =0; i <15; i++){// Every time gc() is triggered,age+1 records the age field is 4 bits maximum 1111 corresponding to 15
            System.gc();// Trigger garbage collection 15 times -- T1 survive T1 to enter the old age
        }
        Teacher T2 = new Teacher();
        T2.setName("B");
        T2.setSexType(MAN_TYPE);
        T2.setAge(18);
        Thread.sleep(Integer.MAX_VALUE);// Thread sleep later to see if T2 is still in the new generation}}class Teacher{
    String name;
    String sexType;
    int age;

    public String getName(a) {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getSexType(a) {
        return sexType;
    }
    public void setSexType(String sexType) {
        this.sexType = sexType;
    }
    public int getAge(a) {
        return age;
    }
    public void setAge(int age) {
        this.age = age; }}Copy the code
  1. JVM Memory Allocation
  2. Initialize the runtime data area
  3. Class loading

  • Execute method (run main method after loading)

4. Create an object

process

The JVM starts, requests memory, initializes the runtime data area, loads the classes into the method area, and executes the methods. The execution and exit process of the method is reflected in memory as the push and exit of the stack frame in the virtual machine stack. Also, objects created during the execution of the method are generally placed in the heap, and objects in the heap are eventually garbage collected.

  • The heap space is divided into generations

View heap space allocation and memory allocation through HSDB

  • Run the relevant classes first

  • Run the JPS command to view the related processes

  • Find the JDK installation directory java8u292bin bin directory and click hsdb.exe to run the program

  • Click on the image below File to bind the process

    • Enter the process number previously obtained through JPS into the input box
    • After the binding, the process information is displayed on the page

  • throughToolsThe heap parameter column shows the heap allocation
    • We can see that the heap partition is similar to the previous one, so we can see where the heap is, and we can get a better idea of how the JVM virtualizes memory.

  • Object address assignment
    • We can also view the assignment of objects from the Object Histogram

    • The following page is displayed

    • We can search for related classes by their full class name

    • After you find the class you want to look at, you can see that the first line indicates the size and count of all the objects in that class. For example, in red, all the objects of the Teacher class take 48. There are two objects in total. Double-click this column to go to the details page

    • Click the corresponding item, click insperctor below to view the details, and compare it with the previous heap memory address allocation. It is found that one active call GC () slowly enters the old age from the new generation, this A has entered the old age, while the other B is still in the new generation.

View the stack through HSDB

When HSDB binds a process, you can view all the listed thread information by clicking on the thread you want to view, such as main. Click the second one on the float window menu bar to check the stack memory of the main thread, as shown in the figure below.

Interested friends can go to play this tool

Out of memory

Stack overflow StackOverflowError

Method call method recursion

Stack overflow

OOM request to allocate memory space exceeds the maximum heap memory space

You can simulate this by setting the run Settings

You can set the JVM parameters by setting VM Options. For example, you can set the -xms, -xmx parameters to avoid stack overflow

Method area overflow

(1) Run-time constant pool overflow

(2) The Class objects saved in the method area are not reclaimed in time or the memory occupied by Class information exceeds our configuration.

Class recovery conditions
  • All instances of this class have been reclaimed and no instances of this class exist in the heap
  • The ClassLoader that loaded the class has been reclaimed
  • The java.lang.Class object corresponding to this Class is not referenced anywhere, and the methods of this Class cannot be accessed anywhere through reflection.

Direct memory overflow

The capacity of direct memory can be set with MaxDirectMemorySize (default is the same as the maximum heap memory).

A link to the

Java (oracle.com) allows you to view the related parameters