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
- Only.class files can be recognized by the JVM as long as the relevant language files are compiled 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
- just
hotSpot VM
This product is used a lot.hotSpot
Use of permanent generation or meta-space implementation method area Hotspot different versions of the implementation
- just
- In the JVM specification, this is referred to as the method area
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* 10
This step, this is where we jump 7: bipush 10
This 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) * 10
The 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
- JVM Memory Allocation
- Initialize the runtime data area
- 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
- through
Tools
The 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