一.前言

物理机的执行引擎是直接在物理硬件如CPU、操作系统、指令集上运行的,但是对于虚拟机来讲,他的执行引擎由自己实现。 执行引擎有统一的外观(Java虚拟机规范),不同类型的虚拟机都遵循了这一规范,输入字节码文件,解析字节码处理,然后输出结果。

二.运行时栈帧结构

1、栈帧概念
栈帧(Stack Frame)用于支持方法调用和执行的数据结构,包含了局部变量表、操作数栈、动态连接和方法返回地址。

  • 局部变量表大小(max_locals),栈帧深度在编译时已经确定,并写入到了Code属性中;
  • 执行引擎运行的所有字节码指令都只针对当前栈进行操作;

2、局部变量表
局部变量表存储了方法参数以及方法内定义的局部变量。

  • Slot(变量槽):局部变量表容量最小单位,可以存放32位以内的数据类型;
  • refrence:
    • 直接或者间接找到到该对象在“堆内存”中数据存放的起始地址索引;
    • 直接或者间接找到对象所属数据类型在方法区中存储的类型信息;
  • 局部变量表建立在线程的堆栈上,所以操作两个连续的slot是否为原子操作,都不会引起数据安全问题,但是如果是64位的话,不允许任何方式单独访问其中的一个;
  • this:实例方法(非static)默认第一个(第0位索引)slot为当前对象自己的引用;
  • slot重用:
    • 当前字节码的pc计数器超出某个变量的作用域,那这个变量的slot可以交给别的变量使用;
    • 影响到正常的Java垃圾回收机制;
  • 赋null:因为上述slot重用的原因,当方法域内前面有局部变量定义了大内存实际不再使用的变量,紧接着后面的代码又是一个耗时的操作,这个时候及时赋null就显得有大的意义。因为一旦触发后,这部分的slot就可以被重用了。看起来就像是方法区内部进行“类gc"操作一样。但是,并不是任何时候都要进行赋null.以恰当的变量作用域来控制变量回收时间才是最优雅的方式,并且赋null值操作在经过JIT编译优化后会被消除掉,这样的话实际是没有任何意义的。
  • 初始值:和类变量不同,局部变量系统不会自动赋初始值,所以没有赋值是无法使用的,编译都无法通过。即使通过,字节码校验阶段也会检查出来而导致类加载失败;

3、操作数栈(Operand Stack)

  • 操作栈,后入先出;
  • 最大深度:Code属性表中的max_stacks;
  • 32位数据类型所占栈容量为1,64位所占容量为2;
  • 栈元素的数据类型必须和栈指令保持一致
  • 两个栈帧之间可以存在一部分的重叠,共享数据,这样在方法调用的时候避免的额外的参数复制。
  • Java虚拟机的解释执行引擎也是:基于栈的执行引擎;

4、动态连接(Dynamic Linking)
字节码中的方法的调用都是通过常量池中指定方法的符号作为参数

  • 静态解析:这种符号有的是类加载阶段或者首次使用初始化的时候转化为直接的引用
  • 动态连接:另外一部分是在运行时转化为直接引用

5、方法返回地址

  • 退出:

    • 正常退出:遇到返回的字节码指令;
    • 异常退出:本方法异常表中没有匹配的异常;
  • 退出后,恢复上层方法的局部变量表和操作栈,有返回值就把返回值压入上层调用者的栈中;

三.方法调用

定义:确定被调用方法的版本
1、解析

  • 编译器可知,运行期不可变。这类方法的调用成为解析,在类加载阶段进行解析。
  • 静态方法、私有方法、实例构造器方法、父类方法,符合上述条件。特点是:
    • 只能被invokestatic和invokespecial指令调用
    • 不可继承或者重写,编译时已经确定了一个版本。
    • 在类加载时会把符合引用解析为该方法的直接引用。
    • 非虚方法(注意final也是非虚方法,其他的都是虚方法)

2、静态分派

  • 概念:根据静态类型来定位方法的执行版本
  • 典型代表:方法的重载(方法名相同,参数类型不同)
  • 发生时间:编译阶段

3、动态分派

  • 概念:调用invokevirtual时,把常量池中的类方法符号解析到了不同的直接引用上。
  • 典型代表:重写,多态的重要体现
  • 过程:
    • 执行invokevitual指令
    • 在虚方法表(类加载阶段,类变量初始化结束后会初始化虚方法表)中查找方法,没有向上的父类进行查找
  • 方法宗量:方法的接收者与方法参数的总称
  • 单分派和多分派:
    • 只有一个宗量作为方法的选择依据,称为单分派。多个,则称为多分派。
    • 当前的Java是静态多分派、动态单分派的语言;

四.动态语言支持

  • 特点:变量无类型,变量的值才有类型

  • invoke包:Java实现动态语言新增的包

五.指令集

  • 基于栈的指令集

    • 过程:入栈、计算、出栈
    • 优点:
      • 可移植性,不依赖于硬件
      • 代码紧凑
    • 缺点:
      • 速度较慢
      • 产生相当多的指令数量
      • 频繁内存访问
  • 基于寄存器的指令集
    • 代表:x86

六.方法内联

  • 方法内联的方式是通过吧“目标方法”的代码复制到发起调用的方法内,避免真实的方法调用。
  • 内联消除了方法调用的成本,还为其他优化手段建立良好的基础。
  • 编译器在进行内联时,如果是非虚方法,那么直接内联。如果遇到虚方法,则会查询当前程序下是否有多个目标版本可供选择,如果查询结果只有一个版本,那么也可以内联,不过这种内联属于激进优化,需要预留一个逃生门(Guard条件不成立时的Slow Path),称为守护内联。
  • 如果程序的后续执行过程中,虚拟机一直没有加载到会令这个方法的接受者的继承关系发现变化的类,那么内联优化的代码可以一直使用。否则需要抛弃掉已经编译的代码,退回到解释状态执行,或者重新进行编译

七.逃逸分析

逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法里面被定义后,它可能被外部方法所引用,这种行为被称为方法逃逸。被外部线程访问到,被称为线程逃逸。
如果对象不会逃逸到方法或线程外,可以做什么优化?

  • 栈上分配:一般对象都是分配在Java堆中的,对于各个线程都是共享和可见的,只要持有这个对象的引用,就可以访问堆中存储的对象数据。但是垃圾回收和整理都会耗时,如果一个对象不会逃逸出方法,可以让这个对象在栈上分配内存,对象所占用的内存空间就可以随着栈帧出栈而销毁。如果能使用栈上分配,那大量的对象会随着方法的结束而自动销毁,垃圾回收的压力会小很多。
  • 同步消除:线程同步本身就是很耗时的过程。如果逃逸分析能确定一个变量不会逃逸出线程,那这个变量的读写肯定就不会有竞争,同步措施就可以消除掉。
  • 标量替换:不创建这个对象,直接创建它的若干个被这个方法使用到的成员变量来替换。

八.小结

  在前面我们已经了解到栈帧、方法区的内存时线程私有的,本篇更加详细的讲了方法是怎么找到并执行的。Java虚拟机规范:输入字节码,解析字节码处理,输出结果。首先,栈帧包含了局部变量表、操作数栈、动态连接、方法返回地址。字节码中的方法都是通过常量池中的符号作为参数指定的,有些编译解析确定,有些运行行时转化为直接引用。首先记住,JVM是基于栈的执行引擎。栈有着先入后出的特点,执行引擎的指令也仅执行当前栈。而局部变量表存储了方法内需要的变量信息,是以Slot 为单位进行存储,超出操作域后,原本占用的内存区域可以被其他的局部变量使用,类似“回收”。然后,记住Java是静态多分派,动态单分派的语言。静态分派,如方法的重载。通过方法的参数不同就可以确定要调用哪个方法,这个再编译阶段就定好。动态分派,如方法的重写。执行方法时,有一个虚方法表。这这个表里搜索,自己有就执行自己的,没有向上找父类的。这个是Java实现多态的重要原理。Java也有支持动态语言的invoke包,平时用的较少。

深入理解Java虚拟机06--虚拟机字节码执行引擎的更多相关文章

  1. 深入理解java:1.2. 字节码执行引擎

    执行引擎是Java虚拟机的核心组成部分之一. 首先,想想C++和Java在编译和运行时到底有啥不一样? 下图左边,C++发布的就是机器指令, 而下图右边Java发布的是字节码,字节码在运行时通过JVM ...

  2. JVM虚拟机(二):字节码执行引擎

    运行时栈帧结构     栈帧是用于支持虚拟机进行方法调用和方法执行背后的数据结构,它也是虚拟机运行时数据区中的虚拟机栈的栈元素.栈帧存储了方法的局部变量表.操作数栈.动态链接.和方法返回地址等信息. ...

  3. 深入理解java虚拟机(5)---字节码执行引擎

    字节码是什么东西? 以下是百度的解释: 字节码(Byte-code)是一种包含执行程序.由一序列 op 代码/数据对组成的二进制文件.字节码是一种中间码,它比机器码更抽象. 它经常被看作是包含一个执行 ...

  4. 【java虚拟机系列】从java虚拟机字节码执行引擎的执行过程来彻底理解java的多态性

    我们知道面向对象语言的三大特点之一就是多态性,而java作为一种面向对象的语言,自然也满足多态性,我们也知道java中的多态包括重载与重写,我们也知道在C++中动态多态是通过虚函数来实现的,而虚函数是 ...

  5. 《深入理解Java虚拟机》-----第8章 虚拟机字节码执行引擎——Java高级开发必须懂的

    概述 执行引擎是Java虚拟机最核心的组成部分之一.“虚拟机”是一个相对于“物理机”的概念 ,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上的,而 ...

  6. 深入理解Java虚拟机读书笔记5----虚拟机字节码执行引擎

    五 虚拟机字节码执行引擎   1 运行时栈帧结构     ---栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,是虚拟机运行时数据区中的虚拟机栈的栈元素.     ---栈帧中存储了方法的局部变 ...

  7. 深入理解Java虚拟机(类文件结构+类加载机制+字节码执行引擎)

    目录 1.类文件结构 1.1 Class类文件结构 1.2 魔数与Class文件的版本 1.3 常量池 1.4 访问标志 1.5 类索引.父索引与接口索引集合 1.6 字段表集合 1.7 方法集合 1 ...

  8. 深入理解Java虚拟机(字节码执行引擎)

    深入理解Java虚拟机(字节码执行引擎) 本文首发于微信公众号:BaronTalk 执行引擎是 Java 虚拟机最核心的组成部分之一.「虚拟机」是相对于「物理机」的概念,这两种机器都有代码执行的能力, ...

  9. 深入理解JVM虚拟机5:虚拟机字节码执行引擎

    虚拟机字节码执行引擎   转自https://juejin.im/post/5abc97ff518825556a727e66 所谓的「虚拟机字节码执行引擎」其实就是 JVM 根据 Class 文件中给 ...

  10. Java虚拟机-字节码执行引擎

    概述 Java虚拟机规范中制定了虚拟机字节码执行引擎的概念模型,成为各种虚拟机执行引擎的统一外观(Facade).不同的虚拟机引擎会包含两种执行模式,解释执行和编译执行. 运行时帧栈结构 栈帧(Sta ...

随机推荐

  1. C语言小笔记

    头文件的书写 头文件实现函数声明,在使用模板后可以实现一个C文件中即使重复包含某个头文件,在系统中用于只会确认为一个包含 头文件包含可以理解为将头文件内容替换#include“...”行 模板(don ...

  2. 过了所有技术面,却倒在 HR 一个问题上。。

    面试问离职原因,这是我们广大程序员朋友面试时逃不开的问题,如果答得不好,可能就影响了你整个的面试结果. 最近在栈长的Java技术栈vip群里,我也看到大家在讨论这个问题,其中有个朋友的回复栈长很有感触 ...

  3. Api 文档管理系统 RAP2 环境搭建

    Api 文档管理系统 RAP2 环境搭建  发表于 2018-03-27 |  分类于 Api |  评论数: 4|  阅读次数: 4704  本文字数: 4.8k |  阅读时长 ≍ 9 分钟 RA ...

  4. iReport 5.6.0 启动闪退的问题 解决方案

    问题描述 本人使用的Windows版本的 iReport 5.6.0,安装成功后,双击桌面上的iReport-5.6.0图标,出现了闪退,无法正常启动的现象.现象如下: 问题原因 iReport 5. ...

  5. 课程回顾-Structuring Machine Learning Projects

    正交化 Orthogonalization单一评价指标保证训练.验证.测试的数据分布一致不同的错误错误分析数据分布不一致迁移学习 transfer learning多任务学习 Multi-task l ...

  6. 全能系统监控工具dstat

    一.什么是dstat? 通过man帮助,可以看到官方对dstat的定义为:多功能系统资源统计生成工具( versatile tool for generating system resource st ...

  7. JVM读书笔记之OOM

    在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能,本文总结了若干实例来验证异常及发生的场景. 下文代码的开头都 ...

  8. 【原创】驱动加载之OpenService

    SC_HANDLE WINAPI OpenService( _In_ SC_HANDLE hSCManager, _In_ LPCTSTR lpServiceName, _In_ DWORD dwDe ...

  9. eclipse team 没有svn

    从资源库把项目导出来之后 右键点击项目  选择第二个 出现 选择SVN  出现你资源库的地址  finish 完成. 这时项目就会出现地址了 就有提交了

  10. Perl回调函数和闭包

    在Perl中,子程序的引用常用来做回调函数(callback).闭包(closure),特别是匿名子程序. 回调函数(callback) 关于什么是回调函数,见一文搞懂:词法作用域.动态作用域.回调函 ...