JVM combat: JVM runtime data area

insert image description here

What is the connection between JDK, JRE, and JVM?

insert image description here
JVM Java Virtual Machine
JDK Java Development Kit
JRE Java Runtime Environment
The official introduction in the picture above makes it very clear

What is the role of the JVM?

insert image description here
The JVM has two particularly interesting features, language-independent and platform-independent .

Language independence means that the language pair that implements the Java virtual machine specification can run on the JVM, such as Groovy, and the language Scala, which is popular in the field of big data, because the JVM ultimately runs the class file, as long as the final class file is combined with the specification can run on the JVM.

Platform independence means that JVMs installed on different platforms will interpret class files as local machine instructions, thereby realizing Write Once, Run Anywhere

JVM runtime data area

In the process of executing a Java program, the Java virtual machine divides the memory it manages into several different data areas. These areas have their own purposes and the time of creation and destruction. Some areas exist when the virtual machine process is started, and some areas are established and destroyed depending on the start and end of user threads. The memory managed by the Java virtual machine will include the following runtime data areas
insert image description here
where the method area and the heap are the data areas shared by all threads. The program counter, virtual machine stack, and local method stack are thread-isolated data areas, draw a logic diagram
insert image description here

program counter

The program counter is a small memory space that can be thought of as a line number indicator of the bytecode being executed by the current thread

Why record the line number of the bytecode executed by the current thread? Can't you just execute it directly?

Because the code is running in a thread, it is possible for the thread to be suspended. That is to say, the CPU executes thread A for a while, and thread A is suspended before it is finished executing, then executes thread B, and finally executes thread A again. The CPU has to know which part of the instructions to execute thread A, and the thread counter will tell the CPU.

virtual machine stack

The virtual machine stack stores the data, instructions, and return addresses required by the current thread to run the method. The virtual machine stack describes the memory model of Java method execution: each method will create a stack frame to store the local variable table, operand stack, dynamic link, method exit and other information when it is executed . The process of each method from invocation to completion of execution corresponds to the process of a stack frame from being pushed to the stack in the virtual machine stack.

local variable table

The storage storage local variable is a local variable space with a fixed length of 32 bits. The 64-bit long and double types of data occupy 2 local variable spaces (Slots), and the rest of the data types only occupy one. How to store reference types (objects from new)? See the figure below

public int methodOne(int a, int b) {
    
    
	Object obj = new Object();
	return a + b;
}

insert image description here
If the local variable is Java's 8 basic basic data types, it exists in the local variable table, if it is a reference type. Such as String, the reference is stored in the local variable table, and the instance is in the heap.

If the methodOne method calls the methodTwo method, the situation of the virtual machine stack is as follows.
insert image description here
When the virtual machine stack can no longer put down the stack frame, a StackOverflowError will appear, to demonstrate

public class JavaVMStackSOF {
    
    

    private int stackLength = 1;

    public void stackLeak() {
    
    
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) throws Throwable {
    
    
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
    
    
            oom.stackLeak();
        } catch (Throwable e) {
    
    
            System.out.println("stack length: " + oom.stackLength);
            throw e;
        }
    }
}

Set the stack size of the thread at runtime in the idea as follows
insert image description here

The function of the -Xss parameter is to set the stack size of each thread. The larger the value
of
insert image description here
the -Xss parameter, the greater the depth of the print output.

operand stack

Then explain the operand stack , it is relatively easy to understand

There is a Test class as follows

public class Test {
    
    

    public int calc() {
    
    
        int a = 100;
        int b = 200;
        int c = 300;
        return (a + b) * c;
    }

    public int getSum(int a, int b) {
    
    
        return a + b;
    }
}

Decompile it with javap and look at the content of the bytecode file of getSum

javap -v Test
public int getSum(int, int);
  descriptor: (II)I
  flags: ACC_PUBLIC
  Code:
    stack=2, locals=3, args_size=3 //操作数栈大小为2,本地变量表大小为3,入参有3个
       0: iload_1 // 局部变量1压栈
       1: iload_2 // 局部变量2压栈
       2: iadd // 栈顶2个元素相加,计算结果压栈
       3: ireturn
    LineNumberTable: // 指令与代码行数的偏移关系
      line 17: 0
    LocalVariableTable: // 局部变量表
      // 作用域开始位置,作用偏移长度,槽位,变量名,类型描述
      Start  Length  Slot  Name   Signature
          0       4     0  this   Lcom/javashitang/jvm/Test;
          0       4     1     a   I
          0       4     2     b   I

When the Java class is compiled, the size of the operand stack and local variable table has been determined.

The size of the operand stack is 2. The
local variable table has 3 parameters, this, a, b. The this object is implicitly passed by the jvm.
There are three input parameters, this (implicitly passed by the jvm), a, b

LineNumberTable and LocalVariableTable I use the jclasslib Bytecode viewer plugin (it is more convenient to view the bytecode, I generally do not use the javap command) to explain

insert image description here
It can be seen that the 17th line of code in the Test class corresponds to the first line of the getSum method instruction. The
insert image description here
getSum method has 3 local variables
this, the scope of which is [Start PC, Start PC+Length], and the 0th in the local variable table. The location, the type is Test class. The
insert image description here
picture is as follows
insert image description here
. If the input parameter of the getSum method is long, the local variable table is as follows (64-bit long and double type data will occupy 2 local variable spaces (Slot), and the remaining data types are only occupy one)

public long getSum(long a, int b) {
    
    
    return a + b;
}

insert image description here
Note that the position of the local variable table b has changed from 2 to 3, because the variable a has changed from occupying one slot to occupying 2 slots
insert image description here
. Use the execution of the calc method to demonstrate how the program counter, operand stack, and local variable table work together. of

public int calc() {
    
    
    int a = 100;
    int b = 200;
    int c = 300;
    return (a + b) * c;
}

The bytecode of the calc method is as follows . The
insert image description here
execution flow diagram is as follows
Please add image description
. There may be some friends who are not familiar with the function of instructions, so I will briefly introduce them.

In general, the format of the instruction has the following two forms

  1. Operation instructions
  2. Operation instruction operands

istore 100 Store a value from the operand stack to bit 100 of the local variable table
istore_1 Store a value from the operand stack to bit 1 of the local variable table

Why is istore_1 not written as istore 1, or istore 100 as istore_100?

Because the operation of storing a value from the operand stack to the first bit in the local variable table occurs frequently, if istore_1 is used, it will occupy 1 byte, and if istore 1 is used, it will occupy 2 bytes, so using istore_1, you can save space. At the same time, the number of types represented by one byte is limited (128, and various operation instructions in Java occupy 1 byte ), so this form of istore_<n> cannot represent all types of operations, and only a small number of instructions can use istore_<n> , the rest use the form of istore n

So you now understand the reason why the offsets of the instructions in the above picture are not continuous!

Instructions related to the operation type will indicate the type of operation at the very beginning.
insert image description here
bipush: load a constant into the operand stack
istore: store a value from the operand stack to the local variable table
iload: load a local variable into the operation stack
iadd : Only add the top 2 operand stacks, and store the result back to the top of the operand stack

dynamic link

For some methods in Java, the specific execution logic can be known during the class loading process, while some require the specific execution logic (polymorphism) to be determined during the running process. This is the dynamic link at work. I understand, no more analysis.

native method stack

The native method stack (Native Method Stack) and the virtual machine stack lock play a very similar role. The difference between them is that the virtual machine stack serves for the virtual machine to execute Java methods (that is, bytecode), while the native method stack serves. It serves the Native method used by the virtual machine.

Java heap

For most applications, the Java Heap is the largest piece of memory managed by the Java virtual machine lock. The Java heap is a memory area shared by all threads, created when the virtual machine starts. The only purpose of this memory area is to store object instances, almost all object instances allocate memory here

method area

The Method Area, like the Java heap, is a memory area shared by each thread. It is used to store data such as class information, constants, static variables, and code compiled by the real-time compiler that have been loaded by the virtual machine.

JVM memory model

insert image description here
It can be seen from the color that before jdk1.8, the heap memory was divided into the new generation, the old generation, and the permanent band, and the heap memory of jdk1.8 and later was divided into the new generation and the old generation. The new generation area is divided into eden area, s0 area, and s1 area. The default ratio is 8:1:1. The meta space can be understood as direct physical memory.

insert image description here

Reference blog

官方介绍
[1]https://www.oracle.com/technetwork/java/javase/tech/index.html
[2]https://mp.weixin.qq.com/s/Qh9e3bNTcNRaYOft9n7rvg

Guess you like

Origin blog.csdn.net/zzti_erlie/article/details/123379861