java memory region
Parental Delegation Mechanism
The Java Virtual Machine loads the class file on demand, that is, it loads its class file into memory to generate a class object when it is needed, and when loading a class file, the Java Virtual Machine uses a parental delegation mechanism, which handles requests to the parent class, which is a task delegation mode.
How Parental Delegation works
1. When a class loader receives a class loading request, it does not load the class itself first, but delegates a parent class loader to load the class.
2. If there is a parent loader on top of the parent loader, delegate it further, recursively, and finally reach the top-level boot loader (this loader is written by C/C++ and is generally inaccessible.)
3. If the parent loader can successfully load this class, the data that was successfully loaded will be returned. If the parent loader cannot load, the child loader will try to load this class.
class Father { public static void print(String str) { System.out.println("father " + str); } private void show(String str) { System.out.println("father " + str); } } class Son extends Father { } public class VirtualMethodTest { public static void main(String[] args) { Son.print("coder");// father coder } }
Benefits of the Parental Delegation Mechanism:
1. Avoid duplicate loading of classes
2. Protect the security of the program and prevent the core API from being tampered with.
Sandbox security mechanism
This mechanism mainly protects java source code information. If we build our own package that is the same as the source code, such as java/lang/String.Class, when we use the class loader to load this class, in order to prevent your custom class from breaking the source code, he defaults not to use your own system loader for the String class to load it.Instead of your own defined String.class, the error message tells you that there is no main method because the String class under the rt.jar package is loaded, which guarantees the protection of the Java core source code.This is the sandbox protection mechanism.
package java.lang; /** * Report errors: * Error: Main method cannot be found in class java.lang.String. Define main method as: * public static void main(String[] args) * Otherwise, the JavaFX application class must extend javafx.application.Application * */ public class String { public static void main(String[] args) { System.out.println("Hello World"); } }
This program can run, but instead of loading the current java.lang.String, it will load the default java.lang.String package, under which there is no main method, and the current program needs to run the main method, which will cause an error.
jvm virtual machine thread
The java virtual machine defines data areas that are used when programs run, some of which are created with the start of the virtual machine and destroyed with the exit of the virtual machine, while others correspond to threads one-to-one, which are created and destroyed with the start and end of the thread.
1. Each thread: Include program counters, stacks, local stacks independently
2. Sharing between threads: heap, out-of-heap memory space (permanent generation or metaspace, code cache)
1. Threads are running units in a program. JVM allows an application to execute in parallel with multiple threads. In Hotspot JVM, each thread maps directly to the local thread of the operating system.
2. When a java thread is ready to execute, the local thread of an operating system is created at the same time. When the java thread execution terminates, the local thread also recycles.
3. The operating system is responsible for scheduling all threads on an available CPU. Once the local thread is initialized successfully, the program will schedule the run() method of the java thread.
System threads for jvm
If you use jconsole or any debugging tool, you can see that there are many threads running in the background. These background threads do not include the main thread that calls the public static void main(string[]) and the threads that all of the main threads create themselves. These main background system threads are mainly the following in the Hotspot JVM:
Virtual Machine Threads: Thread operations require the JVM to reach a security point before they occur. These operations must occur in different threads because they all require the JVM to reach a security point so that the heap does not change. The types of thread execution include garbage collection for "stop-the-world", thread stack collection, thread suspension, and partial lock undo.
Cyclic Task Threads: Threads that represent time-Cycle events, such as interrupts, are typically used to schedule execution of periodic operations.
GC thread: This thread supports different types of garbage collection behavior in the JVM.
Compile thread: This thread compiles byte code into local code at run time.
Signal Scheduling Thread: This thread receives signals and sends them to the JVM, which is handled internally by calling the appropriate method.
Overview of Runtime Data Area
Runtime data areas can be divided into five main types:
1. Program Counters
2. Virtual Machine Stack
3. Local Method Stack
4. Heap
5. Method Area
Program counter
Program counter registers are small blocks of memory (and the fastest-running storage area)It can be viewed as a line number indicator of the byte code executed by the current thread. In the conceptual model of the java virtual machine, the byte code parser's job is to select the next byte code instruction to execute by changing the value of this counter. It is an indicator of the program control flow, which is required for branch, loop, jump, exception handling, thread recovery, etc.
Multithreading in a Java virtual machine is achieved by switching threads in turn, allocating processor execution time, and a processor (a kernel for a multicore processor) at any given timeOnly instructions from one thread are executed. Therefore, in order for a thread to switch back to the correct execution location, each thread needs to have a separate program counter that does not affect each other and stores independently. We call this type of memory area "thread private" memory, and its life cycle is consistent with that of the thread.
If the thread is executing a Java method, this counter records the address of the virtual machine byte code instruction being executed;If you are executing a native method, this counter value should be empty ((Undefined). This memory region is the only region where no OutOfMemoryError condition is specified in the Java Virtual Machine Specification.
public class PCRegisterTest { public static void main(String[] args) { int a = 10; int b = 20; String c = "123"; System.out.println(c); System.out.println(b-a); } /** * Constant pool: * #1 = Methodref #7.#26 // java/lang/Object."<init>":()V * #2 = String #27 // 123 (Constant Pool) * #27 = Utf8 123 // Get the value of 123 * #37 = Utf8 Ljava/io/PrintStream; * { * public CrazyTest.PcRegister.PCRegisterTest(); * 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 LCrazyTest/PcRegister/PCRegisterTest; * * public static void main(java.lang.String[]); * descriptor: ([Ljava/lang/String;)V * flags: ACC_PUBLIC, ACC_STATIC * Code: * stack=3, locals=4, args_size=1 * 0: bipush 10 * 2: istore_1 * 3: bipush 20 * 5: istore_2 * 6: ldc #2 // String 123 * 8: astore_3 * 9: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; * 12: aload_3 * 13: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V * 16: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; * 19: iload_2 * 20: iload_1 * 21: isub * 22: invokevirtual #5 // Method java/io/PrintStream.println:(I)V * 25: return * LineNumberTable: * line 5: 0 * line 6: 3 * line 8: 6 * line 9: 9 * line 10: 16 * line 11: 25 * LocalVariableTable: * Start Length Slot Name Signature * 0 26 0 args [Ljava/lang/String; * 3 23 1 a I * 6 20 2 b I * 9 17 3 c Ljava/lang/String; * } * SourceFile: "PCRegisterTest.java" */ }
Purpose of stored byte code instructions in PC registers: When a program is running, the CPU needs to continuously switch other threads. When the CPU switches back to the original thread, the CPU knows where to start execution.
The PC register records the execution address of the current thread: The JVM's byte code parser needs to change the value of the PC register to determine what byte code instruction to execute next.
PC registers are set to be thread private: the CPU continuously switches tasks while running, multithreading is a method that executes only one of the threads in a period of time, which necessarily results in interrupts and exceptions. In order to accurately record the address of the current byte code instruction being executed by each thread, a PC register must be provided for each thread so that the thread canCompute independently and do not interfere with each other.
Due to CPU time slice limitations, many threads execute concurrently at any given time, a processor or a kernel in a multicore processor, only one thread's byte code instructions are executed. This requires that each thread be assigned a program counter and stack frame at creation time, and the program counters do not affect each other in each thread.
CPU time slice: The time that the CPU allocates to each program, and each thread is assigned a time slice, called a time slice. Users can open multiple programs to run at the same time, which is assumed to run concurrently under the visual illusion. However, since there is only one CPU at a time, only a portion of what the processor requires at a time can be handled fairly, that is, to reference the time slice so that each program runs concurrently.Programs execute in turn.
java virtual machine stack
Background of virtual machine stack: java language is designed across platforms, java instructions are designed according to stacks, different CPU architectures on different platforms are different, so java cannot be designed based on registers. Advantages are cross-platform, small instruction set, compiler is easy to implement, disadvantage is performance degradation, more instructions are needed to achieve the same function.
Virtual Machine Stack: Like program counters, the Java Virtual Machine Stack is thread-private and has the same lifecycle as the thread. The virtual machine stack describes the thread memory model of Java method execution: When each method is executed, the Java virtual machine synchronously creates a stack frame L (Stack Frame)Used to store information such as local variable tables, operand stacks, dynamic connections, method exits, etc. Each method invoked to the end of execution corresponds to a stack frame (stack frame is the basic data structure that is important for method runtime) from stacking to stacking in the virtual machine stack.(The Java virtual machine stack accesses only as fast as program counters, and there is no garbage collection problem for the stack)
/** * Stack exception * By default: count: 11420 * Set stack size: -Xss256k: count: 2465 */ public class StackErrorTest { private static int count = 1; public static void main(String[] args) { System.out.println(count); count++; main(args);// Maximum local machine to around 11420 } }
Memory allocation for virtual machine stack frames: Some people think that Java memory regions only have heap memory ((Heap) and stack memory (Stack), which is a direct inheritance of the memory layout structure of traditional C, C++ programs (since C/C++ was at its peak when Java came into existence), which is a bit rough in the Java language and the actual partitioning of memory regions is more complex than this.Usually refers to the virtual machine stack, or more often just the local variable table part of the virtual machine stack.
public class StackError { private static int a = 0; public void stackOutError(){ a++; stackOutError(); } public static void main(String[] args) { // The maximum depth of a function call is usually around here. StackError error = new StackError(); try { error.stackOutError(); }catch (Throwable e){ System.out.println("The last a count is = "+a); e.printStackTrace(); } } }
Local variable slots: The storage space of these data types in the local variable table as local variable slots(Slot) denotes that the 64-bit long and double data will occupy two variable slots, while the remaining data types will only occupy one. The memory space required for the local variable table is allocated during compilation. When entering a method, how much local variable space this method needs to allocate in the stack frame is fully determined and will not change the board during method execution.The size of the partial variable table. Size refers to the number of variable slots, how much memory space a virtual machine really uses (for example, 32 bits per variable slot, 64 bits per variable slot, or more) to implement a variable slot, which is entirely up to the specific virtual machine implementation.
One of the effects of local variable slot reuse on garbage collection mechanism
In order to save memory space consumed by stack frames as much as possible, variable slots in the local variable table can be reused. Variables defined in the method body may not necessarily cover the entire method body. If the current value of the byte code PC counter exceeds the scope of a variable, the corresponding variable slot of this variable can be handed over to other variables for reuse.In addition to saving stack frame space, such a design has a few additional side effects, and in some cases, the reuse of variable slots directly affects the garbage collection behavior of the system.
Summary of Virtual Machine Stack Extension: In the Java Virtual Machine Specification, two types of exceptions are specified for this memory area: StackOverflowError exceptions are thrown if the stack depth requested by a thread is greater than the virtual machine's allowable depth, and OutOfMemoryError exceptions are thrown if the Java Virtual Machine Stack capacity can be dynamically expanded if not enough memory is requested when the stack is expanded.
Simulate StackOverFlowError:
public class StackOverFlowTest { private static int a = 0; public static void main(String[] args) { try{ new StackOverFlowTest().test1(); }catch (Exception e){ e.printStackTrace(); System.out.println("a The final value is:"+a); } } public void test1(){ a++; test2(); } public void test2(){ a++; test1(); } }
Simulate OutOfMemoryError exception:
import java.util.ArrayList; import java.util.List; public class OutOfMemory { public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; ; i++){ list.add(new String("OutOfMemory abnormal")); } } }
Limit size in the area where virtual machine memory is configured, -Xmx1m:(set size to 1mb)
The stack capacity of the HotSpot virtual machine is not dynamically expandable, and previous Classic virtual machines were. Therefore, there would be no OutOfM emoryError exception on the HotSpot virtual machine because the virtual machine stack could not be expanded. As long as the thread successfully requested stack space, there would be no OOM, but if the request failed, there would still be an OOM exception.
public class VirtualStack01 { public void methodA(){ int a = 1; int b = 10; methodB(); } public void methodB(){ int k = 2; int m = 20; } public static void main(String[] args) { VirtualStack01 stack01 = new VirtualStack01(); stack01.methodA(); } /** * { * public CrazyTest.VirtualStackTest.VirtualStack01(); * 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 LCrazyTest/VirtualStackTest/VirtualStack01; * * public void methodA(); * descriptor: ()V * flags: ACC_PUBLIC * Code: * stack=1, locals=3, args_size=1 * 0: iconst_1 * 1: istore_1 * 2: bipush 10 * 4: istore_2 * 5: aload_0 * 6: invokevirtual #2 // Method methodB:()V Call Method B * 9: return * LineNumberTable: * line 5: 0 * line 6: 2 * line 7: 5 * line 8: 9 * LocalVariableTable: * Start Length Slot Name Signature * 0 10 0 this LCrazyTest/VirtualStackTest/VirtualStack01; * 2 8 1 a I * 5 5 2 b I * * public void methodB(); * descriptor: ()V * flags: ACC_PUBLIC * Code: * stack=1, locals=3, args_size=1 * 0: iconst_2 * 1: istore_1 * 2: bipush 20 * 4: istore_2 * 5: return * LineNumberTable: * line 11: 0 * line 12: 2 * line 13: 5 * LocalVariableTable: * Start Length Slot Name Signature * 0 6 0 this LCrazyTest/VirtualStackTest/VirtualStack01; * 2 4 1 k I * 5 1 2 m I * * public static void main(java.lang.String[]); * descriptor: ([Ljava/lang/String;)V * flags: ACC_PUBLIC, ACC_STATIC * Code: * stack=2, locals=2, args_size=1 * 0: new #3 Create Object// class CrazyTest/VirtualStackTest/VirtualStack01 * 3: dup * 4: invokespecial #4 // Method "<init>":()V * 7: astore_1 * 8: aload_1 * 9: invokevirtual #5 // Method methodA:()V * 12: return // Set the return value, which is added by default. * LineNumberTable: * line 16: 0 * line 17: 8 * line 18: 12 * LocalVariableTable: * Start Length Slot Name Signature * 0 13 0 args [Ljava/lang/String; * 8 5 1 stack01 LCrazyTest/VirtualStackTest/VirtualStack01; * } */ }
Memory structure of run-time stack frame
Every thread of the java program has its own stack. The data in the stack exists in the format of stack frame. Each method executed on this thread corresponds to a stack frame, which is a memory block or a dataset that stores various data information in the process of method execution.(Method calls correspond to the stacking and stacking of stack frames on the virtual machine stack)
Memory structure of virtual machine stack frame:
1. Table of Local Variables
2. Operand stack
3. Dynamic Links
4. Method return address
5. Additional Information
Each method corresponds to a stack frame in the virtual machine stack from the beginning to the end of execution.
When compiling a java program, how many local variable tables are needed in a stack frame, how deep an operand stack is analyzed and calculated, and written into the Code property of the method table. In other words, how much memory a stack frame needs to allocate is not affected by variable data during the run-time of the program, but only by the source code of the program and the stack of the specific virtual machine implementation.Memory layout form.
From a Java program perspective, all methods on the call stack are executed at the same time and within the same thread. For the execution engine, only the methods on the top of the stack are executed on the active thread, and only the stack frame on the top of the stack is valid, which is called the Current Stack Frame.The method associated with this stack frame is called the Current Method. All byte code instructions run by the execution engine operate only on the current stack frame. If other methods are called in this method, the corresponding new stack frame is created, placed at the top of the stack, and becomes the new current frame.
public class JavaTest { public static void main(String[] args) { try { // There are two ways to end the method: // 1 Normal end, with return as representative // (2) An exception that was not caught and handled during method execution ends by throwing an exception JavaTest test =new JavaTest(); test.methodA(); /** * method1()Start execution... * method2()Start execution... * method3()Start execution... * method3()Coming to an end... * method2()Coming to an end... * method1()End of execution... * main Method end...... */ }catch (Exception e){ e.printStackTrace(); } System.out.println("main Method end......"); } public void methodA(){ System.out.println("method1()Start execution..."); methodB(); System.out.println("method1()end of execution..."); } public int methodB(){ System.out.println("method2()Start execution..."); int i = 10; int m = (int) methodC(); System.out.println("method2()Coming to an end..."); return i + m; } public double methodC(){ System.out.println("method3()Start execution..."); double j = 20.0; System.out.println("method3()Coming to an end..."); return j; } }
Stack frames contained in different threads are not allowed to refer to each other, that is, it is not possible to refer to another thread's stack frame in one stack frame.
If the current method calls another method, when the method returns, the current frame returns the execution result of the method to the previous stack frame, and the virtual opportunity discards the current frame, making the previous stack frame become the current stack frame again.
The java method has two ways of returning functions: one is the normal function return, the return instruction, and the other is throwing an exception, both of which cause the stack frame of the virtual machine to pop up.
Local Variables Table
Local variable tables are called local variable arrays and local variable tables. Local variable tables are defined as an array of numbers that mainly store method parameters and local variables defined within a method. These data are similar to the basic data types, object reference s and returnAddress types.
Because local variables are built on the thread's stack and are private data to the thread, there are no data security issues.
The number of method nested calls is determined by the stack size. Generally speaking, the larger the stack, the more method nested calls. For a function, the more parameters and local variables it has, the larger the local variable table will expand, the larger the stack frame will be to meet the increased need for information to be passed through the method call, and the function call will occupy more stack space, resulting in itsThe number of nested calls decreases.
The variables of the local variable table are only valid in the current method call. When the method executes, the virtual machine uses the local variable table to complete the transfer of parameter values to the parameter variable table. When the method call ends, the local variable table is destroyed as the method stack frame is destroyed.
The parameter values are always stored at the beginning of index0 of the local variable table array until the end of the index whose length is reduced by one.
Local variable table, the most basic unit of storage is Slot (variable slot)
Local variable tables contain eight basic data types known at compile time, variables of reference and returnAddress types.
In the table of local variables, types with less than 32 bits occupy only one slot (including the returnAdres type), while 64-bit types (long and double) occupy two slots.
Note: byte, short, char, is converted to int before storage, boolean is also converted to int type, 0 is false, 1 is true. long and double occupy two slot s.
The JVM assigns an access index to each slot in the local variable table, which provides access to the local variable values specified in the local variable table.
When an instance method is called, its method parameters and the local variables defined within the method body are copied sequentially to each slot in the local variable table.
If you need to access a 64-bit local variable value in a local variable table, you only need to use the previous index.
Local Variables Table is the storage space for a set of variable values that hold method parameters and local variables defined within a method. When a Java program is compiled into a Class file, the maximum capacity of the local variable table that the method needs to allocate is determined in the max_locals data item of the Code property of the method.
When a method is called, the Java Virtual Opportunity uses a local variable table to complete the transfer of parameter values to the list of parameter variables, that is, arguments to parameters. If an instance method is executed (a method not modified by a static)The variable slot of the 0th index in the local variable table defaults to the reference used to pass the instance of the object to which the method belongs, in which the keyword "this" can be usedTo access this implicit parameter. The remaining parameters are arranged in the order of the parameter table, occupying the local variable slot from the beginning. After the parameter table has been allocated, the remaining variable slots are allocated according to the variable order and scope defined internally within the method body.
If the current frame was created by a construction method or an instance method, the object's reference this will be stored in the slot of index0. The rest will be ordered in the parameter table order.
In the stack frame, the local variable table is the most closely related part to performance tuning. When the method is executed, (the virtual machine uses the local variable table to complete the method transfer.)
Variables in the local variable table are also important garbage collection root nodes, as long as objects referenced directly or indirectly in the local variable table are not recycled.
Once the parameter table has been allocated, it is allocated according to the order and scope of the variables defined within the method body. The class variable table has two opportunities to initialize, the first in the Prepare phase, to perform system initialization, to set a zero value for the class variable, and the second in Initialization.Unlike class variable initialization, there is no system initialization process for local variable tables, which means that once a local variable is defined, it must be artificially initialized, otherwise it cannot be used.
The output above will error and the variable m is not initialized.
public class LocalVariablesTest { private int count = 0; public static void main(String[] args) { LocalVariablesTest test = new LocalVariablesTest(); int num = 10; test.test1(); } //Practice: public static void testStatic(){ LocalVariablesTest test = new LocalVariablesTest(); Date date = new Date(); int count = 10; System.out.println(count); //Because this variable does not exist in the local variable table of the current method!! // System.out.println(this.count); } //Understanding the use of Slot public LocalVariablesTest(){ this.count = 1; } public void test1() { Date date = new Date(); String name1 = "www.baidu.com"; test2(date, name1); System.out.println(date + name1); } public String test2(Date dateP, String name2) { dateP = null; name2 = "woshinibaba"; double weight = 130.5;//Occupy two slot s char gender = 'male'; return dateP + name2; } public void test3() { this.count++; } public void test4() { int a = 0; { int b = 0; b = a + 1; } //Variable c uses the slot position occupied by previously destroyed variable b int c = a + 1; } /* Variables are classified according to data type: 1 Basic data type 2 Reference data type According to the position declared in the class: (1) member variables: they all undergo default initialization assignments before being used Class variables: prepare phase of linking: assign default values to class variables---> initial phase: assign explicit values to class variables i.e. static code blocks Instance variables: As the object is created, the instance variable space is allocated in the heap space and assigned by default ② Local variable: must be explicitly assigned before use! Otherwise, compilation fails */ public void test5Temp(){ int num; //System.out.println(num);//Error message: variable num is not initialized } }
Operand Stack (or expression stack)
Operand Stack, also known as the operation stack, is a Last In First Out (LIFO) stack. Like local variable tables, the maximum depth of the operand stack is written to the max_stacks data item of the Code property at compile time. Each element of the operand stack can be any Java data type, including long and double.
An operand stack is a workspace for the JVM execution engine. When a method is first executed, a new stack frame is created, and the operand stack for this method is empty.
32bit The type of takes up a stack unit depth 64bit The type of takes up two stack unit depths
Operand stacks do not access data by accessing indexes, they can only be accessed by standards
If the called method has a return value, its return value will be push ed into the operand stack of the current stack frame and the next byte code instruction to be executed in the PC register will be updated.
The data type of the element in the operand stack must exactly match the sequence of byte code instructions, which is validated by the compiler during the compiler and re-validated during the data flow analysis phase of the class checking phase during class loading. In addition, we say that the interpretation engine of the Java virtual machine is a stack-based execution engine, where the stack refers to the operand stack.
When a method is just starting to execute, its operand stack is empty. During the execution of the method, various byte code instructions are written to and extracted from the operand stack, that is, stack-out and Stack-in operations. For example, arithmetic operations are performed by pressing the stack of operands involved in the operation onto the top of the stack and invoking the operation instructions, for exampleOther methods are called by passing method parameters through the stack of operands. For example, the byte code instruction iadd for integer addition, which runs requiring the two closest elements in the stack to the top of the stack to have two ints stored. When this command is executed, the two ints are stacked, added, and the result is addedRe-stack. The iadd command can only be used to add integers. When it is executed, the data type of the two elements closest to the top of the stack must be int. It cannot be added by a long and a float using the iadd command.
In addition, in the conceptual model, two different stack frames are completely independent of each other as the elements of the virtual machine stack of different methods. However, in most virtual machine implementations, some optimizations are made to make the two stack frames partly overlap. Not only can you save a bit by overlapping part of the operand stack of the following stack frame with part of the local variable table of the above stack frame.Space, and more importantly, a portion of the data can be shared directly when a method call is made without the need for additional parameter replication passes.
java virtual machine compilation code tracking
public class OperandStackTest { public static void main(String[] args) { OperandStackTest test = new OperandStackTest(); System.out.println(test.calc()); // 90000 } public int calc(){ int a = 100; int b = 200; int c = 300; return (a+b)*c; } }
Decompiled byte code file
1. First execute the instruction with offset address 0. The purpose of the Bipush instruction is to push a single-byte integer constant value (-127~128) onto the top of the operand stack, followed by a parameter indicating that the pushed constant value is 100.
2. Execute the instruction with offset address 2. The purpose of the istore_1 instruction is to stack the integer values at the top of the operand stack and store them in the first local variable slot. The next four instructions (up to the instruction with offset address 11) do the same thing, that is, assign variables a, b, c to 100, 200, 300 in the corresponding code.
3. Execute the instruction with offset address 11. The iload_1 instruction copies the integer value of the first variable slot of the local variable table to the top of the operand stack.
4. Execute the instruction with offset address 12. The iload_2 instruction acts like iload_1 by stacking the integer value of the second variable slot.
5. Execute the instruction with offset address 13. The purpose of the iadd instruction is to stack the first two top stack elements on the top of the operand stack, make a reshaping addition, and then put the result on the stack. When the iadd instruction is executed, the original 100,200 in the stack is released, and their sum and 300 are re-stacked.
6. Execute the instruction with offset address 14. The iload_3 instruction stacks 300 stored in the third local variable slot onto the operand stack, where the value of the operand stack is two integer numbers 300. The next instruction imul stacks two elements at the top of the operand stack, makes a reshaping multiplication, and then stacks the result, similar to the execution of the iadd instruction.
7. Execute the instruction with offset address 16. The ireturn instruction is one of the method return instructions. It will end the method execution and return the integer value at the top of the operand stack to the caller of the method. The whole process ends.
Dynamic Linking (Reference to Runtime Constant Pool)
Each stack frame contains a reference to the method that the stack frame belongs to in the run-time constant pool, which is held to support dynamic linking during method invocation.There are a large number of symbol references in the constant pool of Class files, and the method call instructions in byte code take the symbol references pointing to the methods in the constant pool as parameters. Some of these symbol references are converted to direct references during the class loading phase or the first time they are used, which is called static parsing. The other part is converted during each run.For direct reference, this section is referred to as a dynamic connection.
Method return address (Return Address) (definition of method normal exit or abnormal exit)
When a method starts executing, there are only two ways to exit the method. The first way is when the execution engine encounters a byte code instruction (return instruction) returned by either method, and there may be a return value passed to the upper method caller(The method that invokes the current method is called the caller or the main method). Whether or not the method has a return value and the type of return value will be determined by the method in which the return instruction is encountered. This exit method is called Normal Method Invocation Completion.
Another way to exit is to encounter an exception during the execution of a method that is not properly handled within the method body. Whether an exception is generated inside a Java virtual machine or an exception is generated in code using the athrow byte code instruction, the method will exit if no matching exception handler is found in the exception table of this method.The way a method is exported is called Abrupt Method Invocation Completion. A method exits with an exception completion exit and does not provide any return values to its upper callers.
Regardless of the exit mode, after the method exits, it must return to the location where the original method was called before the program can continue executing. When the method returns, it may need to save some information in the stack frame to help restore the execution state of its upper main method. Generally, when the method exits normally, the PC counter value of the main method can be used as a return.Return address, this counter value is likely to be saved in the stack frame. When a method exits abnormally, the return address is determined by the exception handler table, which is generally not saved in the stack frame.
The process of method exit is essentially equivalent to exiting the current stack frame, so the possible actions to perform when exiting are: restoring the local variable table and operand stack of the upper method, pushing the return value (if any) into the operand stack of the caller's stack frame, adjusting the value of the PC counter to point to an instruction following the method call instruction, etc. (Specific to that virtual machine is required)
Some additional information
The Java Virtual Machine Specification allows virtual machine implementations to add information to the stack frame that is not described in the specification, such as information related to debugging and performance collection, which is entirely dependent on the specific virtual machine implementation. Dynamic connections, method return addresses, and other additional information are generally grouped together as stack frame information.
Method calls and method binding mechanisms
Method calls: virtual and non-virtual methods
Referencing symbols as direct references to invoking methods in jvm is related to the binding mechanism of methods. If a method determines the specific version of the invocation at compile time, this version is immutable at run time, and such methods are called non-virtual methods. Static methods, private methods, final methods, instance constructors, and parent methods are all non-virtual methods.Method is called virtual method.
The following method call instructions are provided in the virtual machine:
Common invocation instructions:
1. invokestatic: Call static methods, parse phase determines unique method versions
2. invokespecial: Call methods, private and parent methods, and determine the unique method version during the parsing phase
3. invokevirtual: Call all virtual methods
4. invokeinterface: Call interface methods
Dynamically invoke instructions:
invokedynamic: Resolves dynamically the method to be invoked and executes
The first four instructions are solidified inside the virtual machine, method invocation cannot be performed artificially, and invokedynamic instructions support user-determined method versions.
The invokestatic and invokespecial directives call methods that are not virtual, and the rest (except final-modified ones) are called virtual methods.
@FunctionalInterface interface Func { public boolean func(String str); } public class Lambda { public void lambda(Func func) { return; } public static void main(String[] args) { Lambda lambda = new Lambda(); Func func = s -> { return true; }; lambda.lambda(func); lambda.lambda(s -> { return true; }); } }
Dynamic versus static languages
The difference between them is whether the type check is at compile time or run time, static type language satisfying the type check at compile time, and dynamic type language conversely.
private String str= "abcd"// str = abcd // str is judged to be static type language (strong language, such as java), abcd is judged to be dynamic type language (weak language, such as js,python).
Static type language is the type information that determines the variable itself, dynamic type language Is the type information that determines the value of a variable. Variables have no type information. Variable values have type information.
class Father implements MethodInterface{ public Father() { System.out.println("father Constructor"); } public static void showStatic(String str) { System.out.println("father " + str); } public final void showFinal() { System.out.println("father show final"); } public void showCommon() { System.out.println("father General method"); } @Override public void methodA() { System.out.println("I'm the interface method!"); } } public class Son extends Father{ public Son() { //invokespecial: calls to <init>methods, private and parent methods, the parsing phase uniquely determines the calling method super(); } public Son(int age) { //invokespecial: calls to <init>methods, private and parent methods, the parsing phase uniquely determines the calling method this(); } //Static methods are not overridden parent classes because static methods cannot be overridden! public static void showStatic(String str) { System.out.println("son " + str); } private void showPrivate(String str) { System.out.println("son private" + str); } public void show() { //invokestatic: invokes a static method, the resolution phase uniquely determines the calling method showStatic("www.baidu.com"); //invokestatic super.showStatic("good!"); //invokespecial showPrivate("hello!"); //invokespecial super.showCommon(); //invokevirtual: call all virtual methods showFinal();//This method is also considered non-virtual because it declares final and cannot be overridden by subclasses. //The virtual method is as follows: //invokevirtual showCommon(); info(); MethodInterface in = new Father(); //invokeinterface: invoke interface method in.methodA(); } public void info(){ } public void display(Father f){ f.showCommon(); } public static void main(String[] args) { Son so = new Son(); so.show(); } } interface MethodInterface{ void methodA(); }
Static Link
When a byte code file is loaded inside the jvm, the process of converting the symbolic reference of the calling method to a direct reference is called a static link if the target method being called is known at compile time and does not change at run time.
dynamic link
If the invoked method cannot be confirmed during compilation, it is only possible to convert the symbolic reference of the invoked method to a direct reference during program run time, which is dynamic and is therefore called dynamic link.
class Lesson{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } // Static method: non-virtual method public static void returnName(){ System.out.println("My name is course!"); } } class Teacher extends Lesson implements Method{ private String name; private int age; // Private methods: non-virtual methods private void TeacherName(){ System.out.println("I'm shy. I'm private!"); } // final method: non-virtual method public final void returnData(){ System.out.println("I want to return to a constant! Hello Word!"); } // constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public void teachLesson(String name) { super.setName(name);// Static links, other similar System.out.println("Call the parent constructor method:"+super.getName()); this.age = 24; this.name = "Little Red"; // Call parent static method Lesson.returnName(); returnData(); } @Override public String toString() { this.TeacherName(); return "Teacher{" + "I am:" + name + ",Age is:" + age + ",The courses taught are:"+ super.getName()+ '}'; } } interface Method{ void teachLesson(String name); } public class VirtualMethodTest01 { public static void main(String[] args) { Teacher teacher = new Teacher(); // Runtime only determined: virtual method. teacher.teachLesson("Advanced mathematics");// Dynamic links, other similar System.out.println(teacher.toString()); } }
Result:
Method Binding
The corresponding method bindings can be divided into early and late bindings, where a field, method, or class is replaced with a direct reference at the symbol reference, a process that occurs only once.
Early Binding
Early binding refers to the binding of the method and the type to which the called target method belongs if it is known at compile time and the runtime remains the same. Since it is clear which target method is called, a static connection can be used to convert a symbol reference to a direct reference.
Late Binding
If the method invoked cannot be determined at compile time, it is only possible to bind the related method based on the actual type during program run time, which is called late binding.
class Animal{ public void eat(){ System.out.println("Animal Feeding"); } } interface Huntable{ void hunt(); } class Dog extends Animal implements Huntable{ @Override public void eat() { System.out.println("Dogs eat bones"); } @Override public void hunt() { System.out.println("Prey rats, meddle"); } } class Cat extends Animal implements Huntable{ public Cat(){ super();//Performance as: early binding } public Cat(String name){ this();//Performance as: early binding } @Override public void eat() { super.eat();//Performance as: early binding System.out.println("Cats eat fish"); } @Override public void hunt() { System.out.println("Predatory rat prey"); } } public class AnimalTest { public void showAnimal(Animal animal){ animal.eat();//The manifestation is: late binding } public void showHunt(Huntable h){ h.hunt();//The manifestation is: late binding } }
Thread Security Issues
If only one thread can manipulate this data, it must be thread safe.
If there are multiple threads that can manipulate this data, it is in the memory-sharing area. If synchronization is not considered, then this data is thread-safe.
public class StringBuilderTest { int num = 10; //s1 is declared thread-safe public static void method1(){ //StringBuilder: Thread insecure, no thread synchronization mechanism // StringBUffer: Thread-safe, thread-synchronized, internal methods decorated with synchronized StringBuilder s1 = new StringBuilder(); StringBuffer s2 = new StringBuffer(); s1.append("a"); s1.append("b"); s2.append('c'); s2.append('d'); //... } //sBuilder operation: thread insecure public static void method2(StringBuilder sBuilder){ sBuilder.append("a"); sBuilder.append("b"); //... } //s1 operation: thread insecure public static StringBuilder method3(){ StringBuilder s1 = new StringBuilder(); s1.append("a"); s1.append("b"); return s1; } //Operation of s1: Thread-safe public static String method4(){ StringBuilder s1 = new StringBuilder(); s1.append("a"); s1.append("b"); return s1.toString(); } public static void main(String[] args) { StringBuilder s = new StringBuilder(); new Thread(() -> { s.append("a"); s.append("b"); }).start(); method2(s); } }
Native Method Stack
The virtual machine stack of java manages calls to java methods, while the local method stack manages calls to local methods. (The local method stack thread is private)
Native Method Stacks play a very similar role as the virtual machine stack, except that the virtual machine stack executes Java methods (that is, byte codes) for the virtual machine, while the local method stack serves the local (Native) methods used by the virtual machine.
The language, method and data structure of the local method stack are not mandatory and can be freely implemented as needed. Some java virtual machines directly combine the local method stack with the virtual machine stack (Hotspot JVM)Like virtual machine stacks, local method stacks throw StackOverflowError and OutOfMemory Error exceptions when stack depth overflows or stack expansion fails, respectively.
When a thread calls a local method, it enters a completely new and unrestricted virtual machine with the same permissions as the virtual machine.
Local methods can access the runtime data area inside the virtual machine through the local method interface. It can use the registers of the local processor directly. Allocate any amount of memory directly from the heap of local memory.