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 内存管理

相关内容

热门资讯

折价仍遇冷!大通证券51.59... 7月9日,京东资产交易平台信息显示,大通证券51.59%股权二次拍卖于当日12时结束,因无投资者报名...
踩监管红线!7家民营银行上半年... 2026年以来,银行业严监管趋势持续。《国际金融报》记者梳理发现,2026年上半年,19家民营银行中...
汇率、合资、市场三重影响!江淮... 近日,安徽江淮汽车集团股份有限公司(下称“江淮”)发布了2026年半年度业绩预亏公告。公司预计202...
中国石化完成对中国航油重组 中... 记者从中国石化新闻办获悉,中国石化宣布完成对中国航油的重组工作,中国航油正式成为中国石化二级全资子公...
独家专访马其顿证券交易所CEO... 2026.07.11本文字数:2155,阅读时长大约4分钟作者 |第一财经 航宇、姜一鹤、钱晓鑫、杨...