JVM划分和执行流程

2021-08-12  本文已影响0人  NengLee

JVM

JVM是Java Virtual Machine (Java虚拟机)的缩写,是一种用于计算设备的规范

跨平台

编写Java代码后,编译后会生成.class文件,俗称字节码,而JVM虚拟机就是负责将这些字节码文件翻译成特定平台的机器码后运行,也是说在不同的平台(wind、mac、Linux...)安装不同的JVM虚拟机,那么就可以运行.class,而目前能编译成.class语言也有很多种,如下:

JVM跨平台

优点

缺点

运行时流程图

JVM运行时流程图

类加载器:在以前文章 插件化开发 -- 类加载 有介绍过

运行时数区也是本文的重点

运行时数据区域(重点)

JVM运行时数据区域

定义

当程序Run跑起来,必然会有一个线程(多数为主线程Main-Thread),Java虚拟机会把它所管理的 内存 划分成若干个不同的数据区域

类型

Java方法运行内存区域

有俩大点分别为:程序计数器虚拟机栈

程序计数器

指向当前线程正在执行的字节码指定的地址,一般是对应当前操作数栈的顶端栈帧的位置,防止线程阻塞后被唤醒不知道之前执行的位置点。

虚拟机栈

Java虚拟机栈,除了Native方法需要在本地方法栈计算,Java的一般方法函数计算都是在虚拟机栈完成,具有重要性,具有存储当前线程运行方法,一个方法函数,理解为一个(main-栈帧),栈帧存储了方法局部变量表、操作数栈、动态连接和返回地址等信息。

每一个方法调用至执行完成的过程,都对应着一个栈帧在虚拟机里从入栈到出栈的过程

虚拟机栈(Stack)
方法栈帧

分析操作数栈

一段代码:

    public int add(int a, int b) {
        int c = 0;
        c = a + b;
        return c;
    }

    public static void main(String[] args) {
        Presenter presenter = new Presenter();
        int outcome = presenter.add(10, 20);
    }

通过 javac Presenter.java 编译成class文件,JVM可以编译的文件,

在通过 javap -c Presenter.class JVM将class字节码进行反编译生成汇编代码

  public int add(int, int);
    Code:
       0: iconst_0      //将int类型常量0压入栈, 计数器标记0位置
       1: istore_3      //将int类型值存入局部变量3, 计数器标记1位置
       2: iload_1       //从局部变量1中装载int类型值, 计数器标记2位置
       3: iload_2       //从局部变量2中装载int类型值, 计数器标记3位置
       4: iadd          //执行int类型的加法, 计数器标记4位置
       5: istore_3      //将int类型值存入局部变量3, 计数器标记5位置
       6: iload_3       //从局部变量3中装载int类型值, 计数器标记6位置
       7: ireturn       //从方法中返回int类型的数据, 计数器标记7位置

  public static void main(java.lang.String[]);
    Code:
       0: new           #2  //创建一个新对象   #2动态连   // class com/neng/jvm/Presenter
       3: dup               //复制栈顶数值并将复制值压入栈顶
       4: invokespecial #3  //调用需要特殊处理的实例方法 #3动态连 // Method "<init>":()V
       7: astore_1          //将引用类型或returnAddress类型值存入局部变量1
       8: aload_1           //从局部变量1中装载引用类型值
       9: bipush        10  //将一个10位带符号整数压入栈,   计数器会占用多个9的位置
      11: bipush        20  //将一个20位带符号整数压入栈
      13: invokevirtual #4                  // Method add:(II)I
      16: istore_2          //将int类型值存入局部变量2, 计数器标记为16
      17: return            //从方法中返回,返回值为void

通过指令表操作流程:

局部变量表,类似于数据表,自带物理位置,存储当前(函数)栈帧this常量、计算结果,代码左边

操作数据栈,计算逻辑结果,即使一个常量变量也要先进入栈,再弹栈进入局部表,代码右边

计数器对操作数据栈的位置记录

《JVM 字节码指令集》 帮助查询:

变量到操作数栈:iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_
 
操作数栈到变量:istore,istore_,lstore,lstore_,fstore,fstore_,dstore,dstor_,astore,astore_
 
常数到操作数栈:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_,lconst_,fconst_,dconst_
 
加:iadd,ladd,fadd,dadd
 
减:isub,lsub,fsub,dsub
 
乘:imul,lmul,fmul,dmul
 
除:idiv,ldiv,fdiv,ddiv
 
余数:irem,lrem,frem,drem
 
取负:ineg,lneg,fneg,dneg
 
移位:ishl,lshr,iushr,lshl,lshr,lushr
 
按位或:ior,lor
 
按位与:iand,land
 
按位异或:ixor,lxor
 
类型转换:i2l,i2f,i2d,l2f,l2d,f2d(放宽数值转换)
i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l,d2f(缩窄数值转换)
 
创建类实例:new
 
创建新数组:newarray,anewarray,multianwarray
 
访问类的域和类实例域:getfield,putfield,getstatic,putstatic
 
把数据装载到操作数栈:baload,caload,saload,iaload,laload,faload,daload,aaload
 
从操作数栈存存储到数组:bastore,castore,sastore,iastore,lastore,fastore,dastore,aastore
 
获取数组长度:arraylength
 
检相类实例或数组属性:instanceof,checkcast
 
操作数栈管理:pop,pop2,dup,dup2,dup_xl,dup2_xl,dup_x2,dup2_x2,swap
 
有条件转移:ifeq,iflt,ifle,ifne,ifgt,ifge,ifnull,ifnonnull,if_icmpeq,if_icmpene,
if_icmplt,if_icmpgt,if_icmple,if_icmpge,if_acmpeq,if_acmpne,lcmp,fcmpl
fcmpg,dcmpl,dcmpg
 
复合条件转移:tableswitch,lookupswitch
 
无条件转移:goto,goto_w,jsr,jsr_w,ret
 
调度对象的实例方法:invokevirtual
 
调用由接口实现的方法:invokeinterface
 
调用需要特殊处理的实例方法:invokespecial
 
调用命名类中的静态方法:invokestatic
 
方法返回:ireturn,lreturn,freturn,dreturn,areturn,return
 
异常:athrow
finally关键字的实现使用:jsr,jsr_w,ret

内存区域以及如何分配

JVM在内存处理的流程步骤:

  1. JVM申请内存
  2. 初始化运行时数据区
  3. 类加载
  4. 执行方法栈
  5. 创建对象

其中代码运行Run,不停的对4,5轮询的操作,进栈出栈,进局部变量表

代码对象如何在JVM分配呢?

本地方法栈:

虚拟机栈

程序计数器

方法区

堆区

参考:

《JVM 字节码指令集》

ava虚拟机—栈帧、操作数栈和局部变量表

从 Java 代码如何运行聊到 JVM 和对象的创建-分配-定位-布局-垃圾回收

上一篇 下一篇

猜你喜欢

热点阅读