What is the connection between JDK, JRE, and JVM?
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?
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
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
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;
}
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.
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
The function of the -Xss parameter is to set the stack size of each thread. The larger the value
of
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
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
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
picture is as follows
. 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;
}
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
. 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
execution flow diagram is as follows
. 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
- Operation instructions
- 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.
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
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.
Reference blog
官方介绍
[1]https://www.oracle.com/technetwork/java/javase/tech/index.html
[2]https://mp.weixin.qq.com/s/Qh9e3bNTcNRaYOft9n7rvg