Chapter V virtual machine stack

1. Virtual machine stack overview

Background of virtual machine stack

  1. Due to the cross platform design, Java instructions are designed according to the stack. The CPU architectures of different platforms are different, so it cannot be designed as register based [if designed as register based, the coupling degree is high, and the performance will be improved, because the specific CPU architecture can be optimized, but the cross platform performance is greatly reduced].
  2. The advantages are cross platform, small instruction set and easy implementation of the compiler. The disadvantages are performance degradation and more instructions are required to realize the same function.

Stack and heap in memory

  1. First, the stack is the unit of runtime, while the heap is the unit of storage.
  2. That is: the stack solves the problem of program operation, that is, how to execute the program, or how to process data. Heap solves the problem of data storage, that is, how and where to put the data (stack operation and heap storage)

 

 

Basic content of virtual machine stack

  • What is the virtual machine stack
    • Java Virtual Machine Stack, also known as Java stack in the early days. When each thread is created, it will create a virtual machine stack, which stores stack frames one by one, corresponding to Java method calls. The stack is private to the thread
public class StackTest {

    public static void main(String[] args) {
        StackTest test = new StackTest();
        test.methodA();
    }

    public void methodA() {
        int i = 10;
        int j = 20;

        methodB();
    }

    public void methodB(){
        int k = 30;
        int m = 40;
    }
}

 

  • Lifecycle of virtual machine stack

    • The life cycle is consistent with the thread, that is, the thread ends and the virtual machine stack is destroyed
  • Role of virtual machine stack

    • It is in charge of the operation of Java programs. It saves the local variables of methods (8 basic data types, reference addresses of objects) and some results, and participates in the call and return of methods.
    • Local variable, which is compared with member variable (or attribute)
    • Basic data type variable VS reference type variable (class, array, interface)
  • Stack features (advantages)
    • Stack is a fast and effective way to allocate storage, and its access speed is second only to program counter.
    • There are only two direct operations of the JVM on the Java stack:
      • Each method is executed, accompanied by progress (stacking, pressing)
      • Stack out after execution
    • For the stack, there is no garbage collection problem, there is no GC, but there may be OOM

 

 

Face to face questions: what are the exceptions encountered in development?

The Java virtual machine specification allows the size of the Java stack to be dynamic or fixed.

  • If a fixed size Java virtual machine stack is used, the Java virtual machine stack capacity of each thread can be selected independently when the thread is created. If the thread requests to allocate more stack capacity than the maximum allowed by the Java virtual machine stack, the Java virtual machine will throw a stackovlowerror exception.

  • If the Java virtual machine stack can be expanded dynamically and cannot apply for enough memory when trying to expand, or there is not enough memory to create the corresponding virtual machine stack when creating a new thread, the Java virtual machine will throw an "OutofMemoryError" exception.

Demonstrate stackoverflowerror (the main method calls itself). OOM will not be demonstrated. It should be demonstrated when the overall memory is not enough to allocate.

public class StackErrorTest
{
    public static void main(String[] args)
    {
        main(args);
    }
}

 

Set the memory size of the stack

We can use the - Xss # parameter to set the maximum stack space of the thread. The size of the stack directly determines the maximum reachable depth of the function call.

Sets the thread stack size (in bytes). Append the letter k or K to indicate KB, m or M to indicate MB, and g or G to indicate GB. The default value depends on the platform:

Linux/x64 (64-bit): 1024 KB  Linux Default size
macOS (64-bit): 1024 KB
Oracle Solaris/x64 (64-bit): 1024 KB
Windows: The default value depends on virtual memory
The following examples set the thread stack size to 1024 KB in different units:
-Xss1m -Xss1024k -Xss1048576

 

give an example

public class StackErrorTest {
    private static int count = 1;
    public static void main(String[] args) {
        System.out.println(count);
        count++;
        main(args);
    }
}

 

Before setting parameters, the output results are:

11410
11411
Exception in thread "main" java.lang.StackOverflowError
    at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)

 

This indicates that the stack overflowed at the depth of 11411

After setting stack parameters:

 

2458
Exception in thread "main" java.lang.StackOverflowError
    at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)

2. Storage unit of stack

The above has a certain understanding of the virtual machine stack. Now let's take a look at the internal structure of the stack.

What is stored in the stack?

  1. Each thread has its own stack, and the data in the stack exists in the format of Stack Frame
  2. Each method being executed on this thread corresponds to a Stack Frame.
  3. Stack frame is a memory block and a data set, which maintains various data information in the process of method execution.

review:

  • Basic concepts of OOP: class and object
  • Basic structure in class: field (attribute, field, domain), method

Stack operation principle

  1. There are only two direct operations of the JVM on the Java stack, that is, pressing and exiting the stack frame, following the first in first out (LIFO) principle

  2. In an active thread, there will only be one active stack frame at a point in time. That is, only the stack frame (stack top stack frame) of the currently executing method is valid. This stack frame is called the Current Frame. The method corresponding to the current stack frame is the Current Method, and the class that defines this method is the Current Class

  3. All bytecode instructions run by the execution engine only operate on the current stack frame.

  4. If other methods are invoked in the method, the corresponding new stack frame will be created and placed on the top of the stack to become a new current frame.

 

 

  1. The stack frames contained in different threads are not allowed to reference each other, that is, it is impossible to reference the stack frame of another thread in one stack frame.
  2. If the current method calls other methods, when the method returns, the current stack frame will return the execution result of this method to the previous stack frame. Then, the virtual opportunity discards the current stack frame, making the previous stack frame become the current stack frame again.
  3. Java methods have two ways to return functions.
    • One is the normal function return, using the return instruction.
    • The other is to throw an exception when an uncapped exception occurs during method execution.
    • However, no matter which method is used, the stack frame will be ejected.

Methods can be ended in two ways: 1. Normal end, represented by return; 2. An exception that is not captured and handled occurs during the execution of the method, which is thrown in the form of an exception

Internal structure of stack frame

Each stack frame stores:

  • Local Variables

  • Operand Stack (or expression stack)

  • Dynamic Linking (or method reference to runtime constant pool)

  • Method Return Address (or definition of normal or abnormal exit of the method)

  • Some additional information

 

 

Each thread has its own stack, and there are many stack frames in each stack. The size of the stack frame is mainly determined by the local variable table and operand stack

3. Local variable table

  1. Local variable table is also called local variable array or local variable table
  2. Defined as a numeric array, it is mainly used to store method parameters (formal parameters) and local variables defined in the method body. These data types include various basic data types, object references, and returnAddress return value types (return value types). -- the reason why it is a digital array is that the eight basic data types and object references stored can be converted into digital storage.
  3. Since the local variable table is built on the thread stack and is the private data of the thread, there is no data security problem
  4. The required capacity of the local variable table is determined at compile time and stored in the maximum local variables data item of the Code attribute of the method. The size of the local variable table will not be changed during the operation of the method (it will not be changed after the size is determined).
  5. The number of nested method calls is determined by the size of the stack. Generally speaking, the larger the stack, the more nested method calls.
    • For a function, the more its parameters and local variables, the expansion of the local variable table, and the larger its stack frame, so as to meet the demand of increasing the information required for method call.
    • Furthermore, function calls will occupy more stack space, resulting in fewer nested calls.
  6. Variables in the local variable table are valid only in the current method call.
    • When the method is executed, the virtual machine completes the transfer process from the parameter value to the parameter variable list by using the local variable table.
    • When the method call ends, the local variable table will be destroyed with the destruction of the method stack frame.

Example demonstration: demonstrate the meaning of the content after bytecode parsing (you can use javap -v className.class command or jClasslib plug-in) -- here is the demonstration with static method, and there is a little difference between non-static methods.

public static void main(String[] args) {
    LocalVariablesTest test = new LocalVariablesTest();
    int num = 10;
    test.test1();  // This is a call test1 method
}

 

 

 

Here, I explain the starting PC and length. Take 0 and 16 as examples. First of all, we should understand that the starting PC + length = 16 (i.e. bytecode length). Then 0 represents the line number of bytecode instruction, that is, 0 corresponds to new #1, which is the position declared by args. We know from the bytecode and java command correspondence table that 0 corresponds to 9 lines of java code, that is, the command line of localvariablestest = new localvariablestest(). This is the next line for this variable to take effect. That is, the number of lines of the corresponding bytecode file is the line number declared by this variable; The corresponding java command is the next line of the variable declaration (in fact, the next line takes effect because the previous line is a declaration).

Understanding of slot -- the meaning of slot

  1. Parameter values are always stored from the position of local variable array index 0 to the end of the index of array length - 1.
  2. The most basic storage unit of the local variable table is Slot (variable Slot). The local variable table stores various basic data types (8 types), reference types and returnAddress variables known at the compilation time (the local variable table has been determined during compilation).
  3. In the local variable table, types within 32 bits only occupy one slot (including returnAddress type), and 64 bit types occupy two slots (1ong and double) (reference type and returnAddress are both 32 bits, accounting for one slot; long and double are 8 bytes, 8 * 864 bits).
  • byte, short and char are converted to int when storing predecessors, and boolean is also converted to int. 0 means false, and non-0 means true
  • long and double occupy two slot s
  • The JVM will assign an access index to each Slot in the local variable table, and the local variable value specified in the local variable table can be successfully accessed through this index
  • When an instance method is called, its method parameters and local variables defined inside the method will be copied to each slot in the local variable table in order (i.e. sorted according to the declaration order)
  • If you need to access a 64 bit local variable value in the local variable table, you only need to use the previous index. (for example, accessing variables of type long or double)
  • If the current frame is created by the construction method or instance method, the object reference this will be stored in the slot with index 0, and the other parameters will continue to be arranged in the order of the parameter table. (this is also equivalent to a variable). In fact, for non static methods and construction methods, they all have a reference to an object. We can also use this (representing the current object) to call its methods and properties in these methods.
  •  

     

     

    Face-to-face test question: why can't this be used in static methods, but this can be used in instance methods? What is this only?

    The local variable of the calling method is also placed in the stack of the first local variable of the current method. Static methods do not have this reference. Therefore, the instance method can use this, which refers to the current object calling the stack frame.

    Local variable table code demonstration

    public void test1() {
        Date date = new Date();
        String name1 = "atguigu.com";
        test2(date, name1);
        System.out.println(date + name1);
    }

     

    This is the first Slot position of the local variable table of the non static method - this reference

     

     

     

    public String test2(Date dateP, String name2) {
        dateP = null;
        name2 = "songhongkang";
        double weight = 130.5;//Occupy two slot
        char gender = 'male';
        return dateP + name2;
    }

     

     

     

    For constructors, there is only one this.

     

     

    Reuse of Slot

    The slots in the local variable table in the stack frame can be reused. If a local variable passes its scope, it is likely to reuse the slots of expired local variables after declaring the new local variable change after its scope, so as to save resources.

    public void test4() {
        int a = 0;
        {
            int b = 0;
            b = a + 1;
        }
        //variable c Use previously destroyed variables b Occupied slot Location of
        int c = a + 1;
    }

     

    Here we can see that there are four local variables: this, a, b and c. And b is occupied by c after being acted on.

    Example: comparison between static variables and local variables

    Classification of variables:
    1,By data type:① Basic data type  ② Reference data type
    2,According to the position declared in the class:
      2-1,Member variables: all of them have undergone default initialization assignment before use
           2-1-1,Class variable: linking of prepare Stage: assign default values to class variables
                  ---> initial Stage: assign explicit values to class variables, that is, assign values to static code blocks
           2-1-2,Instance variable:With the creation of the object, the instance variable space will be allocated in the heap space and assigned by default
      2-2,local variable: Before use,mustFor explicit assignment! Otherwise, the compilation fails.

     

    public void test() {
        int num;
        System.out.println(num); // Variable 'num' might not have been initialized
    }

     

    This method will be red when written in the compiler, because for local variables, the assignment must be displayed manually. For member variables, it is not necessary to display the assignment. Member variables are divided into class variables and instance variables: their assignment process is different.

    1. After the parameter table is allocated, it is allocated according to the sequence and scope of variables defined in the method body (local variable table).
    2. We know that there are two initialization opportunities for member variables. The first is to perform system initialization in the "preparation stage" and set zero value for class variables. The other is to give the programmer the initial value defined in the code in the "initialization" stage.
    3. Unlike class variable initialization, there is no system initialization process for local variable table, which means that once local variables are defined, they must be initialized manually, otherwise they cannot be used.

    Supplementary notes:

    1. In the stack frame, the part most closely related to performance tuning is the local variable table mentioned earlier. When the method is executed, the virtual machine uses the local variable table to complete the transfer of the method.

    2. The variables in the local variable table are also important garbage collection root nodes. As long as the objects directly or indirectly referenced in the local variable table are not recycled.

    4. Operand stack

    Stack: it can be realized by using array or linked list. The operand stack of JVM is implemented by array.

    1. In addition to the local variable table, each independent stack frame also contains a Last - In - First -Out operand stack, which can also be called Expression Stack

    2. Operand stack: in the process of method execution, write data or extract data to the stack according to bytecode instructions (some of which need to write or output data to the stack), that is, push and pop

      • Some bytecode instructions push the value into the operand stack, while others take the operand out of the stack. Use them and push the results onto the stack

      • For example: copy, exchange, sum and other operations

     

    The CPU does not know this bytecode instruction. In the execution process, the operand stack will be used first. The execution engine will translate this bytecode instruction into machine instructions, and then execute the command with the help of the operand stack.

    1. The operand stack is mainly used to save the intermediate results of the calculation process and serve as the temporary storage space for variables in the calculation process (in fact, it is to store and retrieve data, and then calculate, such as adding, and then put the added results in).

    2. The operand stack is a working area of the JVM execution engine. When a method starts executing, a new stack frame will be created (its internal structure, including the local variable table), and the operand stack of the method is empty (the stack is empty, but it does not mean that it has not been created. Since it is created and the size of the array is determined, we need to think about the length of the empty stack).

    3. Each operand stack will have a clear stack depth for storing values. The maximum depth required is defined at compile time and stored in the Code attribute of the method, which is the value of maxstack.

    4. Any element in the stack can be any Java data type

      • 32bit type occupies a stack unit depth
      • The 64bit type occupies two stack unit depths
    5. The operand stack does not access the data by accessing the index (although it is an array, we access it by entering and exiting the stack). Instead, it can only access the data once through the standard entering and exiting operations. It's just that the operand stack is implemented with the structure of array

    6. If the called method has a return value, its return value will be pushed into the operand stack of the current stack frame, and the next bytecode instruction to be executed in the PC register will be updated.

    7. The data type of the elements in the operand stack must strictly match the sequence of bytecode instructions, which is verified by the compiler during the compiler (because the depth of the operand stack is determined during the compilation period). At the same time, the data flow analysis stage of the class verification stage in the class loading process should be verified again.

    8. In addition, we say that the interpretation engine of Java virtual machine is a stack based execution engine, in which the stack refers to the operand stack.

     

    5. Tracking code

    We have explained the theoretical part of the operand stack above, but it must be very vague after talking, so we will explain it at the code level.

    Java code

    public void testAddOperation() {
        //byte,short,char,boolean: All with int Type to save
        byte i = 15;
        int j = 8;
        int k = i + j;
    
        // int m = 800;
    }

     

    Corresponding bytecode instruction

     0 bipush 15
     2 istore_1
     3 bipush 8
     5 istore_2
     6 iload_1
     7 iload_2
     8 iadd
     9 istore_3
    10 return

     

    Step by step:

    1. First execute the first statement, the PC register points to 0, that is, the instruction address is 0, and then use bipush to put the operand 15 into the operand stack. (at first, the size of the local variable table and operand stack are determined, but they are empty). -- in fact, I have a thought here. Isn't the first position of this local variable table this? In fact, you may have noticed that we don't care about this position.

    • Explain why the local variable table index starts from 1, because this method is an instance method, and this is stored where the local variable table index is 0

     

    2. After execution, the PC register moves down to the next line of code. The next line of code is to store the elements of the operand stack in the location of local variable table 1 (istore_1). We can see that an element has been added to the local variable table. And the operand stack is empty (1 in istore_1 here refers to the position with index 1)

     

    3. The back PC moves down and points to the next line. Let the operand 8 also be put on the stack, execute the store operation at the same time, and store it in the local variable table

    4. Then, from the local variable table, put the data in the operand stack in turn

     

    5,iload_1: Take out the data with index 1 in the local variable table and put it into the operand stack. iload_2: Remove the data with index 2 from the local variable table

    6. Then, the two elements in the operand stack are added and stored in the position of local variable table 3

     

    7. Finally, return is over (no return value)

    bipush, iload and iadd here all involve operand stacks. This istore is saved to the local variable table.

    a minor question:

    Description of type conversion

     

     

    • Because 8 can be stored in byte type, the type of pushed operand stack is byte instead of int, so the bytecode instruction executed is bipush 8
    • However, when stored in a local variable, it will be converted to a variable of type int: iStore_ four

     

    • After m is changed to 800, the byte cannot be stored, so it becomes a short type, sipush 800

    If the called method has a return value, the return value is put into the operand stack

      public int getSum(){
            int m = 10;
            int n = 20;
            int k = m + n;
            return k;
        }
    
        public void testGetSum(){
            //Get the result returned by the previous stack frame and save it in the operand stack
            int i = getSum();
            int j = 10;
        }

     

    getSum() method bytecode instruction: with an ireturn at the end

     

     

    testGetSum() method bytecode instruction: load the return value of getSum() method as soon as it comes up ()

    6. Stack top cache technology

    Top of stack caching

    1. As mentioned earlier, the zero address instructions used by the virtual machine based on the trestle architecture (the stack structure has only in and out of the stack, and no address is required) are more compact, but more in and out of the stack instructions must be used to complete an operation, which also means that more instruction dispatch times will be required (that is, you will find a lot of instructions) and lead to more memory read / write times, which is inefficient.

    2. Since operands are stored in memory, frequent memory read / write operations will inevitably affect the execution speed. In order to solve this problem, the designers of HotSpot JVM put forward the top of stack caching technology, which caches all the top of stack elements in the registers of the physical CPU, so as to reduce the number of reads / writes to the memory and improve the execution efficiency of the execution engine.

    3. The main advantages of registers: fewer instructions and fast execution speed, but there are many instruction sets (i.e. instruction types)

    7. Dynamic link

    (most) bytecode instructions require constant pool access when they are executed.

    Dynamic links (or method references to runtime constant pools)

    1. Each stack frame contains a reference to the method to which the stack frame belongs in the runtime constant pool. The purpose of including this reference is to support the code of the current method to realize Dynamic Linking, such as invokedynamic instruction

    2. When Java source files are compiled into bytecode files, all variable and method references are saved in the constant pool of class files as symbolic references. For example, when a method calls another method, it is represented by the symbolic references to the method in the constant pool. The function of dynamic link is to convert these symbolic references into direct references to the calling method

    public class DynamicLinkingTest {
    
        int num = 10;
    
        public void methodA(){
            System.out.println("methodA()....");
        }
    
        public void methodB(){
            System.out.println("methodB()....");
    
            methodA();
    
            num++;
        }
    
    }

     

    Bytecode translation

    Classfile /F:/IDEAWorkSpaceSourceCode/JVMDemo/out/production/chapter05/com/atguigu/java1/DynamicLinkingTest.class
      Last modified 2020-11-10; size 712 bytes
      MD5 checksum e56913c945f897c7ee6c0a608629bca8
      Compiled from "DynamicLinkingTest.java"
    public class com.atguigu.java1.DynamicLinkingTest
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #9.#23         // java/lang/Object."<init>":()V
       #2 = Fieldref           #8.#24         // com/atguigu/java1/DynamicLinkingTest.num:I
       #3 = Fieldref           #25.#26        // java/lang/System.out:Ljava/io/PrintStream;
       #4 = String             #27            // methodA()....
       #5 = Methodref          #28.#29        // java/io/PrintStream.println:(Ljava/lang/String;)V
       #6 = String             #30            // methodB()....
       #7 = Methodref          #8.#31         // com/atguigu/java1/DynamicLinkingTest.methodA:()V
       #8 = Class              #32            // com/atguigu/java1/DynamicLinkingTest
       #9 = Class              #33            // java/lang/Object
      #10 = Utf8               num
      #11 = Utf8               I
      #12 = Utf8               <init>
      #13 = Utf8               ()V
      #14 = Utf8               Code
      #15 = Utf8               LineNumberTable
      #16 = Utf8               LocalVariableTable
      #17 = Utf8               this
      #18 = Utf8               Lcom/atguigu/java1/DynamicLinkingTest;
      #19 = Utf8               methodA
      #20 = Utf8               methodB
      #21 = Utf8               SourceFile
      #22 = Utf8               DynamicLinkingTest.java
      #23 = NameAndType        #12:#13        // "<init>":()V
      #24 = NameAndType        #10:#11        // num:I
      #25 = Class              #34            // java/lang/System
      #26 = NameAndType        #35:#36        // out:Ljava/io/PrintStream;
      #27 = Utf8               methodA()....
      #28 = Class              #37            // java/io/PrintStream
      #29 = NameAndType        #38:#39        // println:(Ljava/lang/String;)V
      #30 = Utf8               methodB()....
      #31 = NameAndType        #19:#13        // methodA:()V
      #32 = Utf8               com/atguigu/java1/DynamicLinkingTest
      #33 = Utf8               java/lang/Object
      #34 = Utf8               java/lang/System
      #35 = Utf8               out
      #36 = Utf8               Ljava/io/PrintStream;
      #37 = Utf8               java/io/PrintStream
      #38 = Utf8               println
      #39 = Utf8               (Ljava/lang/String;)V
    {
      int num;
        descriptor: I
        flags:
    
      public com.atguigu.java1.DynamicLinkingTest();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: aload_0
             5: bipush        10
             7: putfield      #2                  // Field num:I
            10: return
          LineNumberTable:
            line 7: 0
            line 9: 4
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      11     0  this   Lcom/atguigu/java1/DynamicLinkingTest;
    
      public void methodA();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=1, args_size=1
             0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
             3: ldc           #4                  // String methodA()....
             5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
             8: return
          LineNumberTable:
            line 12: 0
            line 13: 8
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       9     0  this   Lcom/atguigu/java1/DynamicLinkingTest;
    
      public void methodB();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=3, locals=1, args_size=1
             0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
             3: ldc           #6                  // String methodB()....
             5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
             8: aload_0
             9: invokevirtual #7                  // Method methodA:()V
            12: aload_0
            13: dup
            14: getfield      #2                  // Field num:I
            17: iconst_1
            18: iadd
            19: putfield      #2                  // Field num:I
            22: return
          LineNumberTable:
            line 16: 0
            line 18: 8
            line 20: 12
            line 21: 22
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      23     0  this   Lcom/atguigu/java1/DynamicLinkingTest;
    }
    SourceFile: "DynamicLinkingTest.java"

     

    1. In bytecode instruction, method A is called through invokevirtual #7 instruction in methodB() method, so #7 what is it?

    2. Go up and find the definition of constant pool: #7 = methodref #8# thirty-one

    • Find #8:
      • #8 = Class #32: find #32
      • #32 = Utf8 com/atguigu/java1/DynamicLinkingTest
      • Conclusion: through #8 us, we found the class of #DynamicLinkingTest
    • Again #31:
      • #31 = NameAndType #19:#13: find #19 and #13
      • #19 = Utf8 methodA: method name is methodA
      • #13 = utf8() V: the method has no formal parameters and the return value is void

    3. Conclusion: through #7 us, we can find the methodA() method to be called and call it

    4. In fact, there are many symbol references, such as Object, System, PrintStream and so on

     

    For the above figure: why do dynamic links (method references to runtime constant pools) apply constant pools: their function is to convert symbolic references in bytecode into direct references. Why quote? Why not put it directly in the bytecode file? Actually, it's easy to understand. For example, if methodA calls methodB, you cannot put the bytecode file of methodB into methodA. So A is too big. For example, when we write papers and references, you can't take the whole references.

    Why do I need a constant pool?

    The function of constant pool is to provide some symbols and constants for instruction recognition.

    1. Because constants or methods can be called in different methods, you only need to store one copy and record its reference, which saves space.

    2. The function of constant pool is to provide some symbols and constants to facilitate the identification of instructions

    public class OperandStackTest
    {
        int num;
        public void methodA() {
            System.out.println(num);
        }
        public void methodB() {
            System.out.println(num);
        }
    }

     

    For example, this Code: if both methods call num, you don't need to store two copies of num.

    8. Method invocation: parsing and dispatching

    The above describes the local variable table, operand stack and method reference to the runtime constant pool. Let's talk about the method call before talking about the method return address and some additional information. This is the highlight of the rest of the information. It's easy to turn to the method return address and some additional information. We talk about method calls every day in the hope that we can have a deeper understanding of method calls.

    In the JVM, converting a symbolic reference to a direct reference that invokes a method is related to the binding mechanism of the method

    • Static link:

    When a bytecode file is loaded into the JVM, if the called target method is determined during compilation and remains unchanged during runtime, the process of converting the symbolic reference of the calling method into a direct reference is called static link

    • Dynamic link:

    If the called method cannot be determined during compilation, that is, the symbol of the called method can only be converted into direct reference during program running. Because this reference conversion process is dynamic, it is also called dynamic link.

    Early binding and late binding

    Static links and dynamic links are for methods. The scope of early binding and late binding is wider. Early binding covers static links and late binding covers dynamic links.

    The binding mechanisms of the methods corresponding to static links and dynamic links are Early Binding and Late Binding. Binding is the process of replacing a field, method, or class with a direct reference when a symbolic reference is replaced, which occurs only once.

    • Early binding

    Early binding means that if the called target method is known at compile time and remains unchanged at run time, this method can be bound with its type. In this way, since it is clear which target method is called, the symbolic reference can be converted into direct reference by means of static link.

    • Late binding

    If the called method cannot be determined during compilation, it can only bind the relevant method according to the actual type during program running. This binding method is also called late binding.

    package com.atguigu.java2;
    
    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 on mice and mind your own business");
        }
    }
    
    class Cat extends Animal implements Huntable {
    
        public Cat() {
            super();//Performance: early binding
        }
    
        public Cat(String name) {
            this();//Performance: early binding
        }
    
        @Override
        public void eat() {
            super.eat();//Performance: early binding
            System.out.println("Cats eat fish");
        }
    
        @Override
        public void hunt() {
            System.out.println("It's natural to prey on mice");
        }
    }
    
    public class AnimalTest {
        public void showAnimal(Animal animal) {
            animal.eat();//Performance: late binding
        }
    
        public void showHunt(Huntable h) {
            h.hunt();//Performance: late binding
        }
    }

     

     

    9. Method return address

     

    10. Some additional information

     

    11. Stack related interview questions

     

     

    Tags: jvm

    Posted by fansa on Thu, 14 Apr 2022 05:42:22 +0930