JVM学习笔记 03 - 字节码
创始人
2025-05-29 05:25:15

字节码

        一句话概括 JVM 与操作系统之间的关系:JVM 上承开发语言,下接操作系统,它的中间接口就是字节码

  • JVM:等同于操作系统;
  • Java 字节码:等同于汇编语言。

        Java 字节码一般都比较容易读懂,这从侧面上证明 Java 语言的抽象程度比较高。你可以把 JVM 认为是一个翻译器,会持续不断的翻译执行 Java 字节码,然后调用真正的操作系统函数,这些操作系统函数是与平台息息相关的。

        使用 JDK 的工具 javac 进行编译后,会产生 HelloWorld 的字节码。
        我们一直在说 Java 字节码是沟通 JVM 与 Java 程序的桥梁,下面使用 javap 来稍微看一下字节码到底长什么样子。

0 getstatic #2 
3 ldc #3 
5 invokevirtual #4 
8 return

        Java 虚拟机采用基于栈的架构,其指令由操作码和操作数组成。这些字节码指令,就叫作 opcode。其中,getstatic、ldc、invokevirtual、return 等,就是 opcode,可以看到是比较容易理解的。
        我们继续使用 hexdump 看一下字节码的二进制内容。与以上字节码对应的二进制,就是下面这几个数字(可以搜索一下)。

b2 00 02 12 03 b6 00 04 b1

注意:这里是二进制文件的16进制表示,也就是hex,一般分析二进制文件都是以hex进行分析。

        我们可以看一下它们的对应关系。

0xb2   getstatic       获取静态字段的值
0x12   ldc             常量池中的常量值入栈
0xb6   invokevirtual   运行时方法绑定调用方法
0xb1   return          void 函数返回

代码例子

public long test(long);descriptor: (J)Jflags: ACC_PUBLICCode:stack=4, locals=5, args_size=20: aload_01: getfield      #2                  // Field a:I4: i2l5: lload_16: ladd7: getstatic     #3                  // Field C:J10: ladd11: lstore_312: lload_313: lreturnLineNumberTable:line 13: 0line 14: 12LocalVariableTable:Start  Length  Slot  Name   Signature0      14     0  this   LB;0      14     1   num   J12       2     3   ret   J

执行过程

        回顾一下 JVM 运行时的相关内容。main 线程会拥有两个主要的运行时区域:Java 虚拟机栈和程序计数器。其中,虚拟机栈中的每一项内容叫作栈帧,栈帧中包含四项内容:局部变量报表、操作数栈、动态链接和完成出口。
我们的字节码指令,就是靠操作这些数据结构运行的。下面我们看一下具体的字节码指令。

        字节码的执行流程可以这样理解:字节码在Java虚拟机栈中被执行,每一项内容都可以看作是一个栈帧,栈帧的结构包括局部变量表、操作数栈、链接、返回地址。这时候就很明了了,栈帧的执行流程就是字节码的执行流程了。类中变量会被解析到局部变量表,然后对操作数栈进行入栈出栈的操作,在此期间有可能引用到动态或静态链接,最后把计算结果的引用地址返回。

查看字节码

命令行查看字节码

        使用下面的命令编译源代码 A.java。如果你用的是 Idea,可以直接将参数追加在 VM options 里面。

javac -g:lines -g:vars A.java

        这将强制生成 LineNumberTable 和 LocalVariableTable。
        然后使用 javap 命令查看 A 和 B 的字节码。

javap -p -v A
javap -p -v B

        这个命令,不仅会输出行号、本地变量表信息、反编译汇编代码,还会输出当前类用到的常量池等信息。

可视化查看字节码

        我们可以使用更加直观的工具 jclasslib,来查看字节码中的具体内容了。

        我们观察到还有 LineNumberTable 等选项,该属性的作用是描述源码行号与字节码行号(字节码偏移量)之间的对应关系。有这些信息,在 debug 时,就能获取到发生异常的源代码行号。 

第04讲:动手实践:从栈帧看字节码是如何在 JVM 中进行流转的

第02讲:大厂面试题:你不得不掌握的 JVM 内存管理

相关内容

热门资讯

第141期:49.05 2025年12月19日更新:【#大V综合信号#】49.05不买不卖(上期50.50)
“海南封关后不能寄快递”属谣言 原标题:互联网辟谣平台12月22日今日辟谣 2025年12月22日 今日辟谣 辟 谣 官方辟谣“海南...
一拖再拖!募投项目多次延期,天... “好人家”火锅底料的母公司天味食品(603317.SH)募投项目又延期了。近日,天味食品发布公告表示...
黄金的“疯狂星期一” 价格再创... 文/陶思阅 12月22日,黄金价格创下历史新高。现货黄金日内涨近1.5%,站上4400美元/盎司,创...