中间变量缓存机制原理(Java代码反汇编解析)

今天遇到一个奇怪的小问题,在给变量赋值的时候遇到一个中间变量缓存机制的问题,所以自己准备把这个坑挖到低,总结一下,希望各路大佬来批评。

上最简易版“坑”代码:

public class TestDemo2 {

	public static void main(String[] args) {
		int i = 0;
		i = i++;
		System.out.println("result : "+i);
	}
}

刚开始我会以为答案是1,结果后来发现运行台和我想法不一致。。。

竟然输出为 result : 0 !!!

然后从网上搜了一下,发现是中间变量缓存机制的问题,emmm。。就是说,先给i赋完0值后,然后对于i = i++;这行代码的处理为:

  1. 把i 的初值0 放入操作数栈(虚拟机栈是描述java方法执行的内存模型,每个方法执行的时候都会创建一个栈帧用于存放局部变量表,操作栈,动态链接,方法出口等信息,每一个方法在执行到结束过程中都在虚拟机栈完成了入栈出栈的过程,局部变量表存放了编译期间可知的各种基本类型(boolean、byte、char、short、int、float、long、double),对象引用,根据不同的虚拟机表现可能不一致,有可能是句柄引用,也可能是直接引用。局部变量表所需的内存空间在编译期间完成分配,运行期间不会改变大小)。
  2. i++,此时的 i 的确变为 1 了,一切正常,关键是第三部!
  3. 刚开始放入堆栈的0 弹出,赋值给 i ! 看吧,问题就在这里,赋值语句会将之前暂存的0值重新放回来。 

很多人到这里基本上就明白了,但是秉着有坑就要挖到底的原则又开始折腾起来了,首先打开生成的class路径下,不知道位置在哪的看这里(项目右键):

很明显我的就是在TestDemo项目的bin目录下,然后找到这个路径会发现自己的class文件就在这里躺着(如果没有的话使用Eclipse 运行一下代码)。

在此处打开命令行,输入 javap -c TestDemo.class(javap是jdk自带的反解析工具。它的作用就是根据class字节码文件,反解析出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息)。

输出结果如下:

相信很多人对这个可能不太熟悉,其实这很简单的,只需要对着相应的命令一行行看就行,现在很明显可以看到main方法,然后还有code:标识,下面开始解析:

  • iconst_0 :其实 int i =0 ;这不是一个原子操作,这个的含义是先定义一个0放入局部变量表,然后把0 赋值给 i, 所以iconst_0就是 定义第一个变量。
  • istore_1:那这个的含义就是把局部变量表中的数赋值给第一个变量,注意啊,这个1是值第一个变量,那第一个变量肯定就是i 了。
  • iload_1:这个就好理解了,就是把第一个变量放入堆栈,也就是i = i++;中,先把 后面的 i 值放入堆栈。
  • iinc   1,1:这个的含义为自增操作,第一个变量自增1,就是相当于i++的操作了,如果这里就终止的话,那肯定i 就是1 了,但是后面赋值操作才是关键。
  • istore_1:将堆栈中的变量弹出,赋值给i ,哈哈哈 ,i 又回来了!
  • 。。。

下面的代码不做解析了,很明显都是对system.out的解析,详细的 jvm 反汇编解析请问百度,谷歌,必应。。。

完工!

附录:

iconst_<i> 代表了一个指令族,它的意思是把整数 i 放入操作数栈中,i 的范围是(m1, 0, 1, 2, 3, 4, 5),其中 m1 代表的是 -1。注意,这里的 i 并不是指令的操作数(即非嵌入式操作数,也非栈内操作数),如 iconst_1、iconst_2 和 iconst_3 都是由一个字节组成的字节码指令。我们可以把 i 可以看作是指令的 “隐含操作数”,即指令本身就蕴含了操作数。如果整数 i 超过 [-1, 5] 这个范围,就不能用 iconst_<i> 表示了,因为仅一个字节的字节码指令不可能蕴含所有的整数。此时就需要 bipush 这条指令了,这条指令有一个嵌入式操作数,由一个字节组成,用来表示要放入栈顶的那个整数,该整数放入栈顶时通过扩展符号位变为 32 位的整型。但是一个字节也表示不了所有的整数,如果整数值超过一个字节所能表示的范围,就只能通过 ldc 这条指令了,这条指令带有一个字节的嵌入式操作数,它代表的是一个指向运行时常量池中 Constant_Integer_info 类型常量的索引,通过索引的方式引用运行时常量池中的整数,再大的整数也不怕了。

 

--------------------------------------

Forrest   一个有梦想的程序员

点播关注不迷路。

欢迎大佬来尬聊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值