Memory changes during method execution in Java


Preface

  To truly master Java, memory analysis is necessary. Once the memory allocation is mastered, we can accurately predict the execution result of the program before the program is running. This article will explain the memory of the program, for example: Where are the code fragments stored? When the method is called, where to open up memory space, etc.

One, JVM memory structure

The following figure is a diagram of the JVM standard memory structure.
Insert picture description here  Currently, we only focus on **"stack" and "method area" .
  When the Java program starts to execute, first find the bytecode (.class file) on the hard disk through the class loader subsystem, then load it into the method area of ​​the JVM, and start calling the main method. The moment the main method is called, it will Assign the activity space to the main method in the "stack" memory. At this time, a stack push occurs and the activity space of the main method is at the bottom of the stack.
  Since the stack is characterized by first-in
-last-out **, the method that is called first (first pushes the stack) must end last (last pops the stack). So the main method is called first, so it must be the last one to end. In other words, the main method ends, and the program ends.

Two, analyze the memory changes of the program

public class MethodTest {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("main begin");
        m1();
        System.out.println("main over");
    }
    public static void m1(){
    
    
        System.out.println("m1 begin");
        m2();
        System.out.println("m1 over");
    }
    public static void m2(){
    
    
        System.out.println("m2 begin");
        System.out.println("m2 over");
    }
}

The results are as follows:

Insert picture description here
  Let's analyze the memory changes of this code, as shown in the following figure:

Insert picture description hereThe text description is as follows:

  1. The class loader loads the class file into the method area
  2. Start calling the main method, allocate space in the stack memory for the main method, start executing the main method, and output "main begin"
  3. Call the m1() method and allocate space in the stack memory for the m1() method. At this time, the m1() method is at the top of the stack and has the right to be active, and output "m1 begin"
  4. Call the m2() method and allocate space in the stack memory for the m2() method. At this time, the m2() method is at the top of the stack and has the right to be active. It outputs "m2 begin" and continues to output "m2 over"
  5. m2() method execution ends, memory is released, stack is popped
  6. The m1() method is at the top of the stack at this time, has the right to be active, and outputs "m1 over"
  7. m1() method execution ends, memory is released, stack is popped
  8. The main() method is at the top of the stack, has the right to be active, and outputs "main over"
  9. The main() method execution ends, the memory is released, and the stack pops up
  10. The stack is empty and the program ends

to sum up

  The execution of the code in the method body is sequential, and must be executed line by line in a top-down order, which means that the current line of code must be executed before the next line of code can be executed, and it cannot be skipped. Then, we combine the data structure of the stack and think about it together. The reason for using the stack data structure is very clear. Only the use of this advanced and last-out stack data structure can ensure the execution order of the code.

Guess you like

Origin blog.csdn.net/m0_46988935/article/details/110132407