Java is an interpreted language. First, it needs to be compiled into a class file and then loaded by the JVM. Finally, the JVM will interpret it into machine code that the system can run directly. In terms of performance, it is certainly not as good as directly compiling into machine code, so why doesn't Java directly compile into machine code? Because different operating systems have different rules for identifying machine codes, and we only write one copy of code. The JVM is responsible for escaping into machine codes under different operating systems. The benefits are: compile once and run everywhere
The above figure shows the memory model in which the JVM loads class es into memory. In addition to cross platform, the benefits brought by the JVM also include automatic memory allocation, which is also the focus we need to understand. When c/c + + programmers want to use a large amount of data, they need to dynamically apply for memory and manually release the memory at an appropriate time. Once they forget to release, resulting in wild pointers, memory leakage will occur. The JVM helps us free from the tedious work of applying for memory and freeing memory
2, Thread sharing and private
When the JVM runs the program, it is divided into two data areas, a shared data area and a private data area
1. Shared data areaImagine which of the following Java code is fixed? What code is dynamic? Fixed can be expressed in text, such as class name, properties in class, constants, method name, code execution order, etc. It's actually the code we wrote Dynamic is something that cannot be represented by text, such as the value obtained by a series of operations on a variable. In fact, it is an operation that requires cpu intervention
Next, look at a piece of code:
public class Hello { public int test() { int a = 3; int b = 4; return a + b; } public static void main(String[] args) { Hello h = new Hello(); h.test(); } }1.1 method area
After compiling with javac, we get the class file. If we run the program and execute the main function, in which the hello object is instantiated, the JVM will load the class file and store it in the method area (meta space)
Hello.class loading.png
At this time, the class file has been escaped. We can use the javap command to decompile to see what the above code looks like in the JVM
javap -v Hello.class
There is no need to take a closer look. The test method will be described in detail later
Classfile /C:/Users/tyqhc/Documents/javaworkspace/myJava/out/production/myJava/Hello.class Last modified 2021-9-27; size 525 bytes MD5 checksum 74b6dc87932a59d4af95208b0eb1edb7 Compiled from "Hello.java" public class Hello SourceFile: "Hello.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #5.#25 // java/lang/Object."<init>":()V #2 = Class #26 // Hello #3 = Methodref #2.#25 // Hello."<init>":()V #4 = Methodref #2.#27 // Hello.test:()I #5 = Class #28 // java/lang/Object #6 = Utf8 <init> #7 = Utf8 ()V #8 = Utf8 Code #9 = Utf8 LineNumberTable #10 = Utf8 LocalVariableTable #11 = Utf8 this #12 = Utf8 LHello; #13 = Utf8 test #14 = Utf8 ()I #15 = Utf8 a #16 = Utf8 I #17 = Utf8 b #18 = Utf8 main #19 = Utf8 ([Ljava/lang/String;)V #20 = Utf8 args #21 = Utf8 [Ljava/lang/String; #22 = Utf8 h #23 = Utf8 SourceFile #24 = Utf8 Hello.java #25 = NameAndType #6:#7 // "<init>":()V #26 = Utf8 Hello #27 = NameAndType #13:#14 // test:()I #28 = Utf8 java/lang/Object { public Hello(); 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 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHello; public int test(); flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=1 0: iconst_3 1: istore_1 2: iconst_4 3: istore_2 4: iload_1 5: iload_2 6: iadd 7: ireturn LineNumberTable: line 4: 0 line 5: 2 line 7: 4 LocalVariableTable: Start Length Slot Name Signature 0 8 0 this LHello; 2 6 1 a I 4 4 2 b I public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #2 // class Hello 3: dup 4: invokespecial #3 // Method "<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #4 // Method test:()I 12: pop 13: return LineNumberTable: line 11: 0 line 12: 8 line 13: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 args [Ljava/lang/String; 8 6 1 h LHello; }
Each class in Java (we won't discuss internal classes) corresponds to a class file. The information of the class file (class meta information) is stored in the method area, which is a shared data area, and only one copy of the same class loader will be loaded. When we need to instantiate the object of this class, we will find it from the method area. If it has been loaded before, we can use it directly. Anyone can instantiate this class. Naturally, it is stored in the shared data area
1.2 reactorThe method area stores class information, and the heap stores instantiated objects. Objects of the same class can be instantiated multiple times. Objects can be used by other threads, so the heap is also a shared data area. When instantiating an object, there is an object header in the object, in which a type pointer will point to the class meta information in the method area. Just take a look at the figure below. There is no need to delve into it
Object header composition.png
2. Private data areaIn addition to the method area and heap, all other data areas are private data areas. As mentioned earlier, private data areas are data of method runtime and require cpu intervention
2.1 stack frameJava stack is also called virtual machine stack and thread stack. It doesn't matter what it is called. What matters is the content: stack frame
The stack frame is mainly composed of four parts:
- Local variable table: stores local variables and their values
- Operand stack: stores temporary data during operation
- Dynamic links: polymorphic correlation
- Method exit: enter the stack frame of the next method
When each method is called, a new stack frame will be created, and then the code in the method will be executed. The assembly instruction in the test method above is:
0: iconst_3 1: istore_1 2: iconst_4 3: istore_2 4: iload_1 5: iload_2 6: iadd 7: ireturn
A gif diagram is used to show how the test method operates in the stack frame:
2.2 program counter and local method stackProgram counter: the program counter is to temporarily record the line to which the method runs. In fact, there is no parallelism in the program running, but different threads constantly seize the cpu, execute for a period of time, and then start the competition again. However, the execution time is too short, so people can't feel it at all. When a method runs to a certain line, it starts to compete again, You need to record where the current method is running, so that the next time the cpu is preempted by the method, it can continue to execute from the place where it was interrupted last time
Local method stack: the local method stack is used to run c/c + + code. Its structure is the same as that of Java stack. The difference is that the memory dynamically applied by c/c + + code is manually managed by itself
For the memory model, just understand it. For mobile terminal development, we do memory optimization for the memory in the heap. The next article will introduce the memory structure in the heap