JVM字节码加载与存储中的细节

问题引出:

为什么Java定义int型变量为32767时使用的是bipush 32767,而定义int型变量为32768时使用的是 ldc #4 <32768> ?

在 Java 中,如果这样定义int型变量:

java 复制代码
public class Test {

    public static void main(String[] args) {
        int i = 0;
        int j = 5;
        int k = 6;
        int m = 32768;
        int n = 32767;
    }
}

变量对应的字节码文件内容是这样的:

java 复制代码
 0 iconst_0
 1 istore_1
 2 iconst_5
 3 istore_2
 4 bipush 6
 6 istore_3
 7 ldc #2 <32768>
 9 istore 4
11 sipush 32767
14 istore 5
16 return

其中可以看到,当变量值为0~5时,使用的是iconst_x(x为值)的命令来操作的,当变量值为6时,采用bipush 6的命令来操作,但当值为32768时,却采用了ldc命令结合常量池的形式,但是在值为32767时,仍然使用的是sipush 32767的形式来操作的,于是好奇为什么相邻的int值采用了不同的命令来操作。

猜想:与Integer在-128到127之间的值是直接从缓存中取的思路可能一致,为了保证效率而做的优化。

查找资料后,得到的答案是:

核心原因:

是由于 JVM 指令集的设计限制和效率考虑导致的:

bipush 的作用与限制:

  • bipush(byte integer push):将一个 单字节有符号整数 (即范围为 -128 ~ 127)推入操作数栈。
  • 它后面跟的是一个 8位带符号整数(即只能表示 -128 到 127)。

但是!

Java 编译器做了一个"扩展",它允许你在某些情况下使用 bipush 来处理更大一点的整数,比如 short 类型范围内的(-32768 到 32767),但本质上仍然是把值当作 byte 扩展成 int 处理。

不过,一旦超过 127(或小于 -128),就不能再使用 bipush,因为它的参数是 1 字节的有符号整数。

所以:

  • 32767 超过了 bipush 支持的范围(-128 ~ 127),但它仍然能被优化地编码进字节码;
  • 32768 就不能使用 bipush,必须使用更通用的方式加载,如 ldc

ldc 是什么?

  • ldc 是 "load constant" 的缩写。
  • 它从 运行时常量池(Runtime Constant Pool)中加载一个常量值到操作数栈。
  • 可以用于加载:
    • int
    • float
    • String
    • 类引用等复杂结构

当数值超过 bipushsipushiconst_x 等直接加载指令支持的范围时,Java 编译器就会将其放入常量池,并使用 ldc 加载。

具体分析:

数值 使用指令 原因说明
-1 iconst_m1 特殊指令
0 ~ 5 iconst_0, iconst_1 ... iconst_5 有专门的短指令
6 ~ 127 bipush x 单字节可表示
128 ~ 32767 sipush x 使用双字节有符号整数
≥ 32768 ldc #x 放入常量池,使用 ldc 加载

所以:

  • 32767 可以用 sipush 32767(因为是 short 最大值)
  • 32768 已经超过了 short 的最大值(32767),只能用 ldc 加载

✅ 总结:

指令 支持范围 用途说明
iconst_x -1 ~ 5 特定小整数专用指令
bipush -128 ~ 127 单字节整数
sipush -32768 ~ 32767 双字节整数
ldc 任意整数(放入常量池即可) 加载超出上述范围的整数

❗ 结论:

  • 32767 属于 sipush 支持的最大值范围内,所以用 sipush 32767
  • 32768 超出 sipush 范围,必须使用 ldc 从常量池加载

这就是会看到不同指令的原因 ------ 是 JVM 指令设计与编译器优化共同作用的结果

相关推荐
间彧13 小时前
什么是JVM Young GC
java·jvm
顧棟1 天前
JVM本地内存的使用监控情况
jvm
qq_529835351 天前
ThreadLocal内存泄漏 强引用vs弱引用
java·开发语言·jvm
时来天地皆同力.1 天前
Java面试基础:概念
java·开发语言·jvm
hardStudy_h2 天前
C++——内联函数与Lambda表达式
开发语言·jvm·c++
库森学长2 天前
面试官:发生OOM后,JVM还能运行吗?
jvm·后端·面试
描绘一抹色2 天前
JVM基础01(从入门到八股-黑马篇)
jvm
微风粼粼3 天前
程序员在线接单
java·jvm·后端·python·eclipse·tomcat·dubbo
掘金-我是哪吒4 天前
分布式微服务系统架构第158集:JavaPlus技术文档平台日更-JVM基础知识
jvm·分布式·微服务·架构·系统架构