转载

看看 JVM 是怎样消化字节码指令的 ~~

写文章,标题真是个头疼的事儿。写的偏技术点,可能被认为太生硬。写的吸引点儿,可能被认为是「广告」,看着每次阅读量都不到 3%,不由得「老泪纵横」...

看看 JVM 是怎样消化字节码指令的 ~~

如果本文对你有帮助,转发到朋友圈和「在看」支持一下啊。

扯远了,回到我们的正题。不知道你有没有觉得, JVM 也像我们人或者生物一样,执行的过程一如咱们吃东西。只不过他吃的是 .class 文件,把其中认为有营养的常量池、字节码指令等消化吸收,同时一边把垃圾处理掉,在最后不用的时候,再把全部的垃圾unload。

整个 .class 文件中, 字节码指令是很重要的一个部分,所有方法内的逻辑,都是通过这些指令来完成操作。

今天咱就一起来看看指令。

指令

我们前面说过,指令集(ISA)的实现,一般有两种形式

  • 基于寄存器实现
  • 基于栈的实现

两者各有优劣,但对于 JVM 来说,设计者在初期就已经明确了场景和目标,所以JVM实现的指令集是基于栈实现的,具有指令数量少,格式简单,操作数少,易于理解和实现等等特点。

一般一个典型的指令集系统中,需要实现的操作分为以下几类:

  • 数据传送
  • 运算:包括算术运算、逻辑运算和移位运算等
  • 流程控制:控制转移、条件转移、无条件转移以及复合条件转移
  • 中断、同步、图形处理(硬件)等

用通俗的语言描述的话,JVM 这些指令,按革命分工不同,大概干的事儿有:

1.像搬运工一样,来回在局部变量区和操作数栈这两个地方来回挪动数据。比如从局部变量区加载到操作数栈,计算一下,再保存回局部变量区。

  • 这类的命令又根据搬运方向的不同,分为从局部变量表 到 操作数栈的load指令:iload_n、lload_n、aload_n等,分别又对应到不同的操作数类型上,第一个字母基本都代表类型,i -> int, l -> long, a -> 引用。后面的n是数字。
  • 以及分为从 操作数栈到局部变量表 的store指令:istore_n、lstore_n、astore_n等等,类型同上。
  • 还有一些是从常量池直接加载到栈顶的,像ldc、bipush、iconst_i等。

2.像手艺人一样,做些打磨加工的工作,把石头做成雕塑类似的类型转换。比如把int 转成long,把double 转成int这些,对应的JVM 指令是i2l和d2i 2前面是源类型,后面是目标类型。

3.新的生命的孕育,像对象的创建、数组的创建等,以及对类型的操作。创建一个新的类实例 new, 新建一个数组 newarray比如getstatic 是访问类的static 域 、getfield 获取类的实例域 判断对象是否属于特定类型的instanceof

4.像红绿灯一样,指导道路的通行方向,来控制程序流程。有条件的转移:像咱们常用的 if (x == 1) 这种,到了字节码的时候,就变成了if_icmpne还有像try-catch字节码里常看到的 goto,做无条件的跳转。还有一些复合条件的转移,像tableswitch 来支持 switch 语法。而对于 switch 能支持 String ,则是通过编译的时候,把 String 对应的 hashCode取出来,做为int 值来使用,通过 lookupswitch 来处理 case 不连续的情形。

5.像你我程序员一样 :-),在 PM 提过来需求之后, 负责把它实现出来,在JVM里这些是运算指令的活儿。比如int 加法iadd, int 减法isub, 递增iinc这些。

6.还有些函数的调用,执行的返回等等,对于静态和非静态方法,对应的指令稍有差别。像 invokevirtual是调用普通实例方法的,invokestatic 是调用类的静态方法的。以及类的初始化方法init,是通过 invokespecial调用的。方法调用完,一般通过 return结束调用,返回 void, 如果是返回类型数据,则是return,这里的T 和咱们前面说的各种代表数据类型的一样,比如返回int类型的值,对应的指令是 ireturn。

7.异常的情况,通过 athrow指令,抛出去。异常的处理原理,可以参考上一篇文章:你写下的try-catch-finally,在JVM看来不过是...

用来学习的工具

如果对这一部分感兴趣,日常开发中,有几个小工具可以使用。

1.像Java 自带的javap 开箱即用。

2.一个图形界面的工具jclasslib

  • 下载地址:https://github.com/ingokegel/jclasslib/releases

3.IDEA 里面可以安装工具 jclasslib 对应的插件。

看看 JVM 是怎样消化字节码指令的 ~~

相比 javap,图形界面工具除了使用方便,不用命令行,可以方便查看自己编写的代码生成的字节码到底是哪些外,同时各个方法内对应的字节码指令,只要点击一下就能跳转到指令的官方说明,也方便理解和学习。

看看 JVM 是怎样消化字节码指令的 ~~

比如上面的 iconst_2 指令,会跳转到 Oracle 的这个说明页面

看看 JVM 是怎样消化字节码指令的 ~~

原文  http://virtual.51cto.com/art/202004/614893.htm
正文到此结束
Loading...