JVM内存模型

JVM内存模型

JVM内存模型_第1张图片

说明:

1、JVM由装载子系统、运行时数据区(jvm内存模型)、字节码执行引擎;

2、运行时数据区包含堆、元空间、栈、本地方法栈和程序计数器;

3、堆、元空间是线程共享;方法栈、程序计数器是线程独有,每个线程都会有;

4、运行java Calculate.class之后,先由类装载子系统,将字节码文件加载到运行时数据区;

5、栈帧:一个方法对应栈帧,每调用一个方法,会为该方法生成一个栈帧压入方法栈,方法执行完成栈帧弹出。在弹出栈帧之前根据方法出口找到要返回的调用方法的位置;

6、栈帧主要包含:局部变量表、操作数栈、动态链接、方法出口;

7、栈和堆的关系:如果局部变量是对象类型,堆中存放对象的具体内容、栈(的局部变量表)存放内容的引用(地址);

8、方法区和堆的关系:方法区的静态变量是对象的引用(对象在对象的地址);堆存对象的具体的内容;

JVM内存操作过程

通过一个简短的代码说明在jvm内存操作过程:

package com.example.demo;
​
public class Calculate {
​
    public int compute(){
        int a=5;
        int b=7;
​
        return (a+b)*9;
    }
​
    public static void main(String[] args) {
        Calculate calculate = new Calculate();
​
        System.out.println(calculate.compute());
    }
}
​

使用javap -v Calculate.class命令反编译以上类的字节码文件,如下(部分):

{
  public com.example.demo.Calculate();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/example/demo/Calculate;
​
  public int compute();
    descriptor: ()I
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: iconst_5
         1: istore_1
         2: bipush        7
         4: istore_2
         5: iload_1
         6: iload_2
         7: iadd
         8: bipush        9
        10: imul
        11: ireturn
      LineNumberTable:
        line 12: 0
        line 13: 2
        line 15: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      12     0  this   Lcom/example/demo/Calculate;
            2      10     1     a   I
            5       7     2     b   I
​
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #2                  // class com/example/demo/Calculate
         3: dup
         4: invokespecial #3                  // Method "":()V
         7: astore_1
         8: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: aload_1
        12: invokevirtual #5                  // Method compute:()I
        15: invokevirtual #6                  // Method java/io/PrintStream.println:(I)V
        18: return
      LineNumberTable:
        line 19: 0
        line 21: 8
        line 22: 18
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      19     0  args   [Ljava/lang/String;
            8      11     1 calculate   Lcom/example/demo/Calculate;
    MethodParameters:
      Name                           Flags
      args
}
SourceFile: "Calculate.java"
 
  

分析compute()方法的汇编指令执行:

分析compute()方法的汇编指令执行:

public int compute(); descriptor: ()I flags: (0x0001) ACC_PUBLIC

Code:

stack=2, locals=3, args_size=1

0: iconst_5 //将int类型常量5压入栈

1: istore_1 //将int类型值存入局部变量1

2: bipush 7 //将一个8位带符号整数压入栈

4: istore_2 //将int类型值存入局部变量2

5: iload_1 //从局部变量1中装载int类型值

6: iload_2 //从局部变量2中装载int类型值

7: iadd //执行int类型的加法

8: bipush 9 //将一个8位带符号整数压入栈

10: imul //执行int类型的乘法

11: ireturn //从方法中返回int类型的数据

执行流程:

1、将常量5压入操作数栈;

2、将操作数栈顶的值5存入局部变量表1号位置;

3、将整数7压入操作数栈;

4、将操作数栈顶的值7存入局部变量表2号位置;

5、从局部变量1号位置取数压入操作数栈;

6、从局部变量2号位置取数压入操作数栈;

7、将操作数栈顶的两个数相加,并压入栈顶,此时操作数栈只有一个数是5+7=12;

8、将整数9压入操作数栈;

9、将操作数栈顶的两个数相乘,并压入栈顶,此时操作数栈只有一个数是12*9=108;

10、返回计算结果,compute()方法执行完成;

之后,根据compute()方法对应的栈帧的方法出口获得应该返回的main方法的地址,该栈帧从方法栈中弹出,程序回到main方法中继续执行。

你可能感兴趣的:(Java,java,jvm)