深刻了解JVM - 字节码指令

前言

字节码指令的局部更多要和实战搭配学习和应用,所以这一节将会是简略概述字节码的相干指令内容,和class构造不同,字节码指令常见的命令是须要理解的,尽管咱们很多时候并不需要钻研底层字节码的指令,然而譬如动静语言的反对就是通过新增字节码指令实现的。

这一节内容更加倡议配合浏览字节码,依据字节码浏览来增强记忆。后续的文章将会独自开一篇讲一讲字节码的源代码解决。

概述

  1. 理解jvm字节码指令的根本特点
  2. 理解jvm的常见字节码指令(倡议在浏览字节码的时候不晓得什么意思的时候再来查)
  3. 局部指令的解决细节解说。
  4. 最初依据书中的内容整顿了一个excel表格,供浏览的时候进行疾速查阅

字节码指令

简介

java的指令蕴含特定语意操作数字(操作码)并且占一个字节长度的,同时java的指令并不是面向寄存器架构的,而是采纳操作数栈(栈帧)的架构。因为一个字节码的长度被限度为i一个字节,所以意味着操作数字并不可能超过256条(1111 1111)。如果超过长度的下限,就须要依据位操作构建一个新的的数据结构,也能够了解为向上降级,比方byte1降级为byte2就能够如此示意:(byte << 8) | byte2。尽管这种操作会损失肯定的性能,然而换来的是能够省略大量的填充占位符来实现对齐操作。

只有tableswitch 和 lookupswitch 这两条指令例外,须要预留空位来进行对齐填充

反对数据类型

上面是java反对的数据类型表,这里能够看到对于Byte,short,boolean等操作在表上没有的,并不是说不反对,而是jvm解决的时候底层将他们对立作为int操作了,所以只须要依照int的操作了解即可。

指令介绍

因为指令的内容比拟多,这里同样依据书中给的图表作为笔记。

加载指令

加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输,对于局部变量表和操作数栈的内容在之前的文章中都是讲的非常抽象的,简略了解为虚拟机栈的栈帧根底构造中的内容,对于栈桢的具体构造会放到后续的文章解说。

运算指令

运算指令就是咱们常见的数学操作,包含加减乘除以及位移等。这里值得关注的是对于指令的操作 溢出,jvm是如何解决的:

  • 如果除数或者余数是0,则会抛出ArithmeticException异样(运行时异样)
  • 如果数据是整型或者浮点型,进行指令计算的时候如果产生溢出都不会呈现或者抛出异样
  • 整型的溢出会呈现一个不稳固的随机数,并没有规定溢出后为哪一个数字,有可能负数也可能正数。
  • 浮点操作因为存在精度,因而如果呈现非准确的后果会呈现“逐级下溢”的个性,意思就是小数点的局部会舍弃掉,并且舍入到一个不大于原数到最靠近到值。同样,因为精度的存在,无限小数局部会依据精度进行摄入,比方常见的10/3的操作后果。
  • 浮点运算严格依照IEEE 754的标准。

类型转换指令

该指令用于尝试将两个类型进行互转,上面是java反对的宽化类型转化(小类型转大类型):

  • int转long、float、double
  • long类型转 float和double
  • float转double

窄化的范畴转化略微简单一些,他遵循如下的规定:

  • 如果是整型类型,将会间接抛弃位数取得小类型的对应位数,这会导致数字可能变为一个正数(计算机依照最高位为0或者1判断数字的正负值)
  • 如果是浮点型,则遵循如下的规定

    • 如果浮点值是一个NAN,那么转换之后还是NAN
    • 如果向下转型之后,如果不是无穷大,则依照IEEE 754的向零舍入模式取整,取得整数值v,如果v在其数据范畴的容许范畴之内则不变,否则依照向下转型所能示意的最大值(或最小值)示意。
    • 如果Double向下转型无奈被float浮点值,则依照float的正负值0进行示意。如果转化绝对值太大,则依据float的最大值示意。对于double类型的NaN值将按规定转换为float类型的NaN值

对象创立与拜访指令

这里只须要留神创立实例和创立数组应用了不同的命令即可。

操作数栈的指令

操作数栈的指令指的是堆栈之中操作的指令

控制指令

管制转移指令能够让Java虚拟机有条件或无条件地从指定地位指令(而不是管制转移指令)的下 一条指令持续执行程序,从概念模型上了解,能够认为控制指令就是在有条件或无条件地批改PC存放 器的值。这里须要留神的内容是Java辨别了援用类型和根底类型的比拟操作,并且有不同的指令进行辨别,另外,之前提到过的boolean、byte、short 等指令是通过int类型进行比拟的

办法调用和返回指令(重点):

这一块是重点内容,也是有可能会被问到的点,当然具体的实操在后续的文章解说:

invokevirtual指令:用于调用对象的实例办法,依据对象的理论类型进行分派(虚办法分派), 这也是Java语言中最常见的办法分派形式。invokeinterface指令:用于调用接口办法,它会在运行时搜寻一个实现了这个接口办法的对象,找 出适宜的办法进行调用。invokespecial指令:用于调用一些须要非凡解决的实例办法,包含实例初始化办法、公有办法和 父类办法。invokestatic指令:用于调用类静态方法(static办法)。invokedynamic指令:用于在运行时动静解析出调用点限定符所援用的办法。并执行该办法。后面 四条调用指令的分派逻辑都固化在Java虚拟机外部,用户无奈扭转,而invokedy namic指令的分派逻辑 是由用户所设定的疏导办法决定的。

invokedynamic指令是这一块内容的重点,至于办法分派的内容,同样会在后续的文章进行解说。

最初,办法的返回指令是依据数据类型确定的,比方int、double、float的返回类型指令是不一样的。这里也要再次阐明一下,byte、boolean、short这些数据类型的返回值同样是看作int解决的。(能够看到int的重要性了)

异样解决指令

这里又一个考点,须要重点记忆:而在Java虚拟机中,解决异样(cat ch语句)不是由字节码指令来实现的(很久之前已经应用jsr和 ret指令来实现,当初曾经不必了),而是采纳异样表来实现。

同步指令

Java虚拟机能够反对办法级的同步和办法外部一段指令序列的同步,同步一段指令集序列通常是由Java语言中的synchronized语句块来示意的,Java虚拟机的指令集中 有monitorentermonitorexit两条指令来反对synchronized关键字的语义,正确实现synchronized关键字 须要Javac编译器与Java虚拟机两者独特合作反对。

这里给出了具体的一段代码示例:

可查字节码指令表

这里集体依据书中的内容整顿了一份字节码指令的查阅表,用了石墨文档不便随时查阅。

地址:https://shimo.im/sheets/GyrHQ... 《字节码指令》

总结

字节码指令的重点是办法的调用相干内容,在面试当中有可能会被问到JDK个性的是如何通过字节码实现的,同时有必要查看java的虚办法(就是最为常见的办法调用)是如何调用和实现的,借此也能够了解重载和重写的实现。

写在最初

这一节的内容其实并不需要背诵,了解有一个根底的印象即可,这部分也不是背的重点。

能够看到,专栏到了前面的内容少数都是从书上总结了,咱们不须要深刻底层,所以周大神的书多翻翻根本就够了,另外JVM更多还是要本人做笔记总结。