JVM-七步带你掌握JVM内存结构

一、从房屋户型图理解JVM的内存划分原理与基本结构介绍

JVM-七步带你掌握JVM内存结构_第1张图片

大白话:

        这是JDK1.6的内存结构,JDK1.8以后方法区已经挪出来了,不属于JVM内存。

JVM-七步带你掌握JVM内存结构_第2张图片JVM-七步带你掌握JVM内存结构_第3张图片

JVM-七步带你掌握JVM内存结构_第4张图片

JVM-七步带你掌握JVM内存结构_第5张图片

二、第一步:掌握程序计数器的功能与工作过程

JVM-七步带你掌握JVM内存结构_第6张图片

JVM-七步带你掌握JVM内存结构_第7张图片

JVM-七步带你掌握JVM内存结构_第8张图片

JVM-七步带你掌握JVM内存结构_第9张图片

mac@MacdeMBP ch2_class_loader % javap -v PC
警告: 二进制文件PC包含ch2_class_loader.PC
Classfile /Users/mac/IdeaProjects/OOM/OOM/out/production/OOM/ch2_class_loader/PC.class
  Last modified 2023-12-29; size 491 bytes
  MD5 checksum b0849816b5a32d4c8412bfd0452f93e2
  Compiled from "PC.java"
public class ch2_class_loader.PC
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#21         // java/lang/Object."":()V
   #2 = Class              #22            // ch2_class_loader/PC
   #3 = Class              #23            // java/lang/Object
   #4 = Utf8               
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lch2_class_loader/PC;
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               args
  #14 = Utf8               [Ljava/lang/String;
  #15 = Utf8               i
  #16 = Utf8               I
  #17 = Utf8               j
  #18 = Utf8               StackMapTable
  #19 = Utf8               SourceFile
  #20 = Utf8               PC.java
  #21 = NameAndType        #4:#5          // "":()V
  #22 = Utf8               ch2_class_loader/PC
  #23 = Utf8               java/lang/Object
{
  public ch2_class_loader.PC();
    descriptor: ()V
    flags: 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 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lch2_class_loader/PC;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        10
         2: istore_1
         3: bipush        20
         5: istore_2
         6: iload_1
         7: iload_2
         8: if_icmple     18
        11: iload_1
        12: iload_2
        13: iadd
        14: istore_3
        15: goto          22
        18: iload_1
        19: iload_2
        20: isub
        21: istore_3
        22: return
      LineNumberTable:
        line 5: 0
        line 6: 3
        line 8: 6
        line 9: 11
        line 10: 15
        line 11: 18
        line 13: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      23     0  args   [Ljava/lang/String;
            3      20     1     i   I
            6      17     2     j   I
      StackMapTable: number_of_entries = 2
        frame_type = 253 /* append */
          offset_delta = 18
          locals = [ int, int ]
        frame_type = 3 /* same */
}
SourceFile: "PC.java"
mac@MacdeMBP ch2_class_loader % 

JVM-七步带你掌握JVM内存结构_第10张图片

JVM-七步带你掌握JVM内存结构_第11张图片

三、第二步:掌握虚拟机栈的功能与故障实战新

JVM-七步带你掌握JVM内存结构_第12张图片

大白话:

        function() -> function1() -> function2() -> function3() -> function2() -> function1() -> function(), 结果必须等所有方法依次执行完,再依次返回结果,在这个过程中,每个方法的信息不能丢掉,保存在栈帧。

        1.一个线程一次只能执行一个方法

        2.先进后出

        3.栈帧 - 存储当前方法的一些特征

JVM-七步带你掌握JVM内存结构_第13张图片

大白话:

        经常见到异常StackOverFlow,就是因为方法递归层次过深,或者方法内部创建的对象过多导致栈空间不足,就会发生栈溢出错误。

JVM-七步带你掌握JVM内存结构_第14张图片

四、掌握虚拟机栈的内部结构

JVM-七步带你掌握JVM内存结构_第15张图片

大白话:

        1.局部变量表 - 保存方法中的变量;

        2.操作数栈 - 执行方法运算;

        3.动态链接 - 执行方法调用;

        4.方法返回地址 - 返回值

       

局部变量表、操作数栈的大小在字节码生成的时候,就已经确定了,具体如下图:

JVM-七步带你掌握JVM内存结构_第16张图片

JVM-七步带你掌握JVM内存结构_第17张图片

大白话:

        上图的

        stack - 操作数栈的大小 单位:单位空间

        locals - 本地变量的数量 

        Slot - 变量的大小,比如int - 32位(4个字节),long - 64位(8个字节)、short - 16位(2个字节)、byte - 8位(1个字节)、float - 32位(4个字节)

32位表示1个slot

参考:Java虚拟机(三)—— Java变量在虚拟机中的内存分配_java虚拟机内存分配-CSDN博客

JVM-七步带你掌握JVM内存结构_第18张图片

JVM-七步带你掌握JVM内存结构_第19张图片

JVM-七步带你掌握JVM内存结构_第20张图片

警告: 二进制文件StackTest3包含ch2_class_loader.StackTest3
Classfile /Users/mac/IdeaProjects/OOM/OOM/out/production/OOM/ch2_class_loader/StackTest3.class
  Last modified 2024-1-2; size 603 bytes
  MD5 checksum e3eb2d1910da782f57543dfac3b9ba3e
  Compiled from "StackTest3.java"
public class ch2_class_loader.StackTest3
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#28         // java/lang/Object."":()V
   #2 = Double             30.0d
   #4 = Methodref          #5.#29         // ch2_class_loader/StackTest3.test:()V
   #5 = Class              #30            // ch2_class_loader/StackTest3
   #6 = Class              #31            // java/lang/Object
   #7 = Utf8              
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lch2_class_loader/StackTest3;
  #14 = Utf8               test
  #15 = Utf8               a
  #16 = Utf8               I
  #17 = Utf8               b
  #18 = Utf8               c
  #19 = Utf8               d
  #20 = Utf8               D
  #21 = Utf8               e
  #22 = Utf8               main
  #23 = Utf8               ([Ljava/lang/String;)V
  #24 = Utf8               args
  #25 = Utf8               [Ljava/lang/String;
  #26 = Utf8               SourceFile
  #27 = Utf8               StackTest3.java
  #28 = NameAndType        #7:#8          // "":()V
  #29 = NameAndType        #14:#8         // test:()V
  #30 = Utf8               ch2_class_loader/StackTest3
  #31 = Utf8               java/lang/Object
{
  public ch2_class_loader.StackTest3();
    descriptor: ()V
    flags: 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 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lch2_class_loader/StackTest3;

  public static void test();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=7, args_size=0
         0: bipush        10
         2: istore_0
         3: bipush        10
         5: istore_1
         6: bipush        10
         8: istore_2
         9: ldc2_w        #2                  // double 30.0d
        12: dstore_3
        13: ldc2_w        #2                  // double 30.0d
        16: dstore        5
        18: return
      LineNumberTable:
        line 5: 0
        line 6: 3
        line 7: 6
        line 8: 9
        line 9: 13
        line 10: 18
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            3      16     0     a   I
            6      13     1     b   I
            9      10     2     c   I
           13       6     3     d   D
           18       1     5     e   D

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: invokestatic  #4                  // Method test:()V
         3: return
      LineNumberTable:
        line 13: 0
        line 14: 3
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  args   [Ljava/lang/String;
}
SourceFile: "StackTest3.java"
mac@MacdeMacBook-Pro ch2_class_loader % 

查看代码流程

第一步:

JVM-七步带你掌握JVM内存结构_第21张图片

大白话:

        在main方法里,code这里

        0:invokestatic #4      // Method test:()V        - 这里注释都明白告诉了,这里是个方法调用,方法名是test,返回值是V,也就是void;

第二步,查找#4:

JVM-七步带你掌握JVM内存结构_第22张图片

大白话:

        #4 - 就是一个方法调用,指向了StackTest3的test方法;

        #4 又指向了#5.#29

JVM-七步带你掌握JVM内存结构_第23张图片

        #5 - 就是StackTest3这个类

JVM-七步带你掌握JVM内存结构_第24张图片

        #29 - 就是test这个方法

        #29 又指向了#14:#8

JVM-七步带你掌握JVM内存结构_第25张图片

#14:#8 - 就是test():V

总结:所有的#..都不是在内存中,而是在字节码文件中,所以,就像是一个房子的图纸,符号引用转为转为直接引用,就是把#4转为拿到在堆中的地址。

静态解析 - 类加载的时候,就将符号引用转换为直接引用;

动态解析 - 在方法里,单独来创建,单独来使用,在运行的时候才转换为直接引用,这就是动态解析。

JVM-七步带你掌握JVM内存结构_第26张图片

JVM-七步带你掌握JVM内存结构_第27张图片

大白话:

        方法3执行的指令是10,执行方法4返回指令是11,就将指令11传给方法4,返回的时候,将指令11和执行结果一起返回。

五、图解虚拟机栈与PC协调工作过程

JVM-七步带你掌握JVM内存结构_第28张图片

警告: 二进制文件MathTest包含ch2_class_loader.MathTest
Classfile /Users/mac/IdeaProjects/OOM/OOM/out/production/OOM/ch2_class_loader/MathTest.class
  Last modified 2024-1-2; size 543 bytes
  MD5 checksum a2e3adc0a61580b4f5260d7d2bf8ef50
  Compiled from "MathTest.java"
public class ch2_class_loader.MathTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#23         // java/lang/Object."":()V
   #2 = Class              #24            // ch2_class_loader/MathTest
   #3 = Class              #25            // java/lang/Object
   #4 = Utf8              
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lch2_class_loader/MathTest;
  #11 = Utf8               calc
  #12 = Utf8               ()I
  #13 = Utf8               a
  #14 = Utf8               I
  #15 = Utf8               b
  #16 = Utf8               c
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               args
  #20 = Utf8               [Ljava/lang/String;
  #21 = Utf8               SourceFile
  #22 = Utf8               MathTest.java
  #23 = NameAndType        #4:#5          // "":()V
  #24 = Utf8               ch2_class_loader/MathTest
  #25 = Utf8               java/lang/Object
{
  public ch2_class_loader.MathTest();
    descriptor: ()V
    flags: 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 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lch2_class_loader/MathTest;

  public int calc();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        11
         2: istore_1
         3: bipush        22
         5: istore_2
         6: bipush        33
         8: istore_3
         9: iload_1
        10: iload_2
        11: iadd
        12: iload_3
        13: imul
        14: ireturn
      LineNumberTable:
        line 5: 0
        line 6: 3
        line 7: 6
        line 8: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      15     0  this   Lch2_class_loader/MathTest;
            3      12     1     a   I
            6       9     2     b   I
            9       6     3     c   I

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 12: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       1     0  args   [Ljava/lang/String;
}
SourceFile: "MathTest.java"
mac@MacdeMacBook-Pro ch2_class_loader % 

JVM-七步带你掌握JVM内存结构_第29张图片

JVM-七步带你掌握JVM内存结构_第30张图片

大白话:

        注意,如果整型常用值不在-128~127之间,这里就不是bipush命令了。

JVM-七步带你掌握JVM内存结构_第31张图片

JVM-七步带你掌握JVM内存结构_第32张图片继续参照上面的流程,将22和33推入操作数栈,然后出栈并存放到局部变量表,结果如下:

JVM-七步带你掌握JVM内存结构_第33张图片

JVM-七步带你掌握JVM内存结构_第34张图片

JVM-七步带你掌握JVM内存结构_第35张图片

指令10执行结果:

JVM-七步带你掌握JVM内存结构_第36张图片

JVM-七步带你掌握JVM内存结构_第37张图片

JVM-七步带你掌握JVM内存结构_第38张图片

JVM-七步带你掌握JVM内存结构_第39张图片

问题1:为什么不是在操作数栈直接计算呢?

答:这是因为有些运算比较复杂,比如a+b*c,此时拿到操作数栈拿到a和b并不能运算,而是要拿到c,先进行b和c的运算。

JVM-七步带你掌握JVM内存结构_第40张图片

问题2:为什么计算时,需要现将局部变量表的变量,拿到操作数栈,而不是直接计算呢?

答:涉及到算法优先级问题,先出栈算出优先级结果,再继续计算。

六、第三步:轻松掌握本地方法(native)接口与线程调用的底层原理

JVM-七步带你掌握JVM内存结构_第41张图片

JVM-七步带你掌握JVM内存结构_第42张图片

JVM-七步带你掌握JVM内存结构_第43张图片

七、直接内存介绍与应用简介

JVM-七步带你掌握JVM内存结构_第44张图片

JVM-七步带你掌握JVM内存结构_第45张图片

JVM-七步带你掌握JVM内存结构_第46张图片

八、第五步:掌握方法区的功能与内部结构(上)

JVM-七步带你掌握JVM内存结构_第47张图片

JVM-七步带你掌握JVM内存结构_第48张图片

JVM-七步带你掌握JVM内存结构_第49张图片

大白话:

        程序在执行的过程中,需要大量的底层的核心类和扩展类的支持。

JVM-七步带你掌握JVM内存结构_第50张图片

JVM-七步带你掌握JVM内存结构_第51张图片

JVM-七步带你掌握JVM内存结构_第52张图片

JVM-七步带你掌握JVM内存结构_第53张图片

JVM-七步带你掌握JVM内存结构_第54张图片

JVM-七步带你掌握JVM内存结构_第55张图片

JVM-七步带你掌握JVM内存结构_第56张图片

大白话:

        1.类型信息 - 类的基础信息,比如是抽象类?

        2.域信息 - 类中定义的变量

        4. 5. 有的时候是单独拎出来,有的时候是归为2

JVM-七步带你掌握JVM内存结构_第57张图片

大白话:

        4.常见类型有七八种,都是经常使用的类型

        3.见下图
JVM-七步带你掌握JVM内存结构_第58张图片

大白话:

        1.变量 -

                如果带final参数,在链接阶段的准备阶段就已经完成初始化了;

                如果不带final参数,在链接阶段,会首先初始化为一个默认值,到了第三阶段(初始化阶段)再将其初始化为对应的值。

九、第五步:掌握方法区的功能与内部结构(下)

JVM-七步带你掌握JVM内存结构_第59张图片

大白话:

        之所以变量叫域,是因为变量可以是类的,也可以是方法的,容易搞混,所以就叫域。

JVM-七步带你掌握JVM内存结构_第60张图片

JVM-七步带你掌握JVM内存结构_第61张图片

解释:

        LineNumberTable:

                line 7: 0

                line 9: 6

前面那个数字对应代码的行号,后面那个数字对应指令数字。

JVM-七步带你掌握JVM内存结构_第62张图片

总结:

        常量池就是把常用的值、方法等放入常量池,方便后面使用。

十、【堆结构】第六步:一步一图剖析JVM的内存分配策略

JVM-七步带你掌握JVM内存结构_第63张图片

JVM-七步带你掌握JVM内存结构_第64张图片

JVM-七步带你掌握JVM内存结构_第65张图片

解释:

        上图为windows下的磁盘清理截图

JVM-七步带你掌握JVM内存结构_第66张图片

JVM-七步带你掌握JVM内存结构_第67张图片

        

你可能感兴趣的:(Java,jvm,java,后端,spring,boot)