美文网首页
JVM-运行时数区

JVM-运行时数区

作者: 麦大大吃不胖 | 来源:发表于2020-12-03 21:22 被阅读0次

    by shihang.mai

    1. 运行时数区组成

    线程私有: PC、jvm stacks、Native method stacks
    线程共享: heap、method area、direct memory

    • PC: 程序计数器。用于存放下一条指令的位置
    • jvm stacks: jvm栈。一个个的栈桢frame,每个方法一个栈桢
    • Native method stacks: 本地方法栈。调用jvm本身方法,例如JNI
    • heap: 堆。用于存放实例对象;1.8后将常量池和静态变量也放在这,1.8前放在方法区
    • method area:方法区,无论是永久代还是元空间都是方法区的实现。它存储了每一个类的结构信息。
    • 栈桢 = local variable table(本地变量表)+operand stack(操作数栈)+dynamic linking(动态连接)+return address(返回地址)
    线程共享区域

    1.1 jvm stack

    jvm栈包括一个个的frame(栈桢,每个方法一个栈桢),而每个frame又包括local variable table(本地变量表)、operand stack(操作数栈)、dynamic linking(动态连接)、return address(返回地址)

    • dynamic linking:

      public void a(){
        b()
      }
      

      b()在方法区中的运行时常量池中有一个符号引用,dynamic linking就是指向这个符号引用。动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用

    包含这个dynamic linking母的,是为了执行invokeDynamic这个底层命令,可以做到反射

    • return address

      public void a(){
        b()
      }
      

      a调用完b后,b方法应该返回到什么地址上,继续执行a

      jvm stack
    • local variable table(本地变量表)、operand stack

      1. 例子1
      public class TestIPulsPlus {
          public static void main(String[] args) {
              int i = 8;
              i = I++;
              //i = ++I;
              System.out.println(i);
          }
      }
      //结果==>8
      
      //The immediate byte is sign-extended to an int value. That value is pushed onto the operand stack.
      //将8压入到操作数栈operand stack
      0 bipush 8
      //The <n> must be an index into the local variable array of the current frame (§2.6). The value on the top of the operand stack must be of type int. It is popped from the operand stack, and the value of the local variable at <n> is set to value.
      //把操作数栈中的8弹出,在本地变量表下标为1的位置,即给i赋值为8
      2 istore_1
      //The <n> must be an index into the local variable array of the current frame (§2.6). The local variable at <n> must contain an int. The value of the local variable at <n> is pushed onto the operand stack.
      //把本地变量表下标为1位置的值压入到操作数栈,即再把8压入到操作数栈  
      3 iload_1
      //The index is an unsigned byte that must be an index into the local variable array of the current frame (§2.6). The const is an immediate signed byte. The local variable at index must contain an int. The value const is first sign-extended to an int, and then the local variable at index is incremented by that amount.
      //将本地变量表下标为1位置的值加1,即本地变量表的8+1=9  
      4 iinc 1 by 1
      //The <n> must be an index into the local variable array of the current frame (§2.6). The value on the top of the operand stack must be of type int. It is popped from the operand stack, and the value of the local variable at <n> is set to value.
      //把操作数栈中的8弹出,在本地变量表下标为1的位置,即给i赋值为8  
      7 istore_1
      //忽略  
      8 getstatic #2 <java/lang/System.out>
      11 iload_1
      //忽略  
      12 invokevirtual #3 <java/io/PrintStream.println>
      15 return
      
      image-20200920113434125 image-20200920114556120
      1. 例子2
      public class TestIPulsPlus {
          public static void main(String[] args) {
              int i = 8;
              int j = I++;
              //i = ++I;
              System.out.println(j);
          }
      }
      //结果==>8
      
      //把8压入操作数栈 operand stack
      0 bipush 8
      //把operand stack弹出,给本地变量表下标为1的位置赋值,即i=8  
      2 istore_1
      //把本地变量表下标为1的位置的值压入operand stack
      3 iload_1
      //将本地变量表下标为1位置的值加1,即本地变量表的8+1=9 
      4 iinc 1 by 1
      //把operand stack弹出,给本地变量表下标为2的位置赋值,即j=8  
      7 istore_2
      8 getstatic #2 <java/lang/System.out>
      11 iload_2
      12 invokevirtual #3 <java/io/PrintStream.println>
      15 return
      
      image-20200920120425794 image-20200920120452927
      1. 例子
      public class TestIPulsPlus {
          public static void main(String[] args) {
              int i = 8;
              //i = I++;
              i = ++I;
              System.out.println(i);
          }
      }
      //结果==>9
      //把8压入操作数栈
       0 bipush 8
      //把8弹出操作数栈,给本地变量表1位置赋值8   
       2 istore_1
      //本地变量表1位置的值8+1=9   
       3 iinc 1 by 1
      //将本地变量表1位置的值压栈
       6 iload_1
      //把9弹出操作数栈,给本地变量表1位置赋值9      
       7 istore_1
       8 getstatic #2 <java/lang/System.out>
      11 iload_1
      12 invokevirtual #3 <java/io/PrintStream.println>
      15 return
      
      image-20200920133413779 image-20200920133455310
      1. 例子
      public class TestIPulsPlus {
          public static void main(String[] args) {
              int i = 8;
              //i = I++;
              int j = ++I;
              System.out.println(j);
          }
      } 
      //结果==>9
      //把8压入操作数栈
       0 bipush 8
      //把8弹出操作数栈,给本地变量表1位置赋值8   
       2 istore_1
      //本地变量表1位置的值8+1=9  
       3 iinc 1 by 1
      //将本地变量表1位置的值压栈
       6 iload_1
      //把9弹出操作数栈,给本地变量表2位置赋值9     
       7 istore_2
       8 getstatic #2 <java/lang/System.out>
      11 iload_2
      12 invokevirtual #3 <java/io/PrintStream.println>
      15 return
      
      image-20200920143806394 image-20200920143855422

      例子5 递归

      public class Hello_04 {
          public static void main(String[] args) {
              Hello_04 h = new Hello_04();
              int i = h.m(3);
          }
      
          public int m(int n) {
              if(n == 1) return 1;
              return n * m(n-1);
          }
      }
      //main() 本地变量表(0-args 1-h 2-i)
      //new 对象,静态变量赋默认值,成员变量赋默认值,向operand stack压入该对象地址
       0 new #2 <com/mashibing/jvm/c4_RuntimeDataAreaAndInstructionSet/Hello_04>
      //复制栈   
       3 dup
      //弹出复制的栈,执行构造方法,静态变量赋初始值,成员变量赋初始值   
       4 invokespecial #3 <com/mashibing/jvm/c4_RuntimeDataAreaAndInstructionSet/Hello_04.<init>>
      //弹出栈,赋值给本地变量表位置为1的值 h=new Hello_04()  
       7 astore_1
      //将本地变量表位置为1的值压栈   
       8 aload_1
      //把3压栈   
       9 iconst_3
      //弹出栈中的Hello_04和3,调用m()
      10 invokevirtual #4 <com/mashibing/jvm/c4_RuntimeDataAreaAndInstructionSet/Hello_04.m>
      //把栈的值(m()返回的值)赋给本地变量表位置为2的值,i=返回值
      13 istore_2
      14 return
      
      //m() 本地变量表(0-this 1-n)
      //把3压栈   
       0 iload_1
      //把1压栈   
       1 iconst_1
      //弹出3和1判断,如果不等跳至7,相等跳至5   
       2 if_icmpne 7 (+5)
      //把1压栈   
       5 iconst_1
      //返回,并把1放入main()操作数栈的栈顶   
       6 ireturn
      //把3压栈   
       7 iload_1
      //把this压栈   
       8 aload_0
      //把3压栈   
       9 iload_1
      //把1压栈   
      10 iconst_1
      //弹出3和1,相减,压栈   
      11 isub
      //弹出栈中的this和3,调用m(),跳到下一个栈桢   
      12 invokevirtual #4 <com/mashibing/jvm/c4_RuntimeDataAreaAndInstructionSet/Hello_04.m>
      //把3和m()返回值弹出,相乘压栈
      15 imul
      //返回,并把栈的值放入main()操作数栈的栈顶      
      16 ireturn
      
      image-20200921134228562 image-20200921134648670 image-20200921134648670 image-20200921134715927

    2. 常用指令

    store:将操作数栈赋值给本地变量表,出栈

    load:将本地变量表的值压栈

    invokeStatic:调用静态方法

    InvokeVirtual:直接用类,调用实例方法。

    invokeSpecial:可以直接定位,不需要多态的方法。privtae&构造方法

    invokeInterface:用接口类型调的方法

    invokeDynamic:lambda表达式,反射,动态语言。动态Class产生的指令

    参考

    https://www.cnblogs.com/ding-dang/p/13051143.html

    相关文章

      网友评论

          本文标题:JVM-运行时数区

          本文链接:https://www.haomeiwen.com/subject/freoiktx.html