通过Java字节码深入理解Java执行过程及JVM底层结构

在读本文时,可以参考我的另外两篇介绍jvm的博客。
JVM底层结构
Java堆内存介绍及简单性能调优

生成一个字节码文件

首先我们编写一个简单的Java文件
在这里插入图片描述
在文件夹中找到这个文件,可以看到只有一个.java 文件
在这里插入图片描述
在命令行使用Javac命令,生成.class文件
在这里插入图片描述
使用Javap -c命令,生成字节码文件
在这里插入图片描述
在这里插入图片描述
看到这个乱七八糟的代码,你可能会问,,这tm是什么鬼。
下面通过JVM指令手册从Java底层对字节码进行分析

字节码分析

一、computer方法:

在这里插入图片描述

代码 int a=1

iconst_1:将int型常量①压入操作数栈
istore_2:将int类型的值存入局部变量①
结合JVM虚拟机内存结构图
在这里插入图片描述
首先,给常量a在操作数栈中分配一个内存空间,即iconst_1对应int a
然后,把常量a的值变成1,并存进局部变量表,即istore_2对应a=1

代码 int b=2

iconst_2:将int型常量②压入操作数栈
istore_2:将int类型的值存入局部变量②
同理,很容易理解

代码 return a+b

iload_1:从局部变量①中转载int类型值 即a的值1
iload_2:从局部变量②中装载int类型值 即b的值2
即把变量a的值1给装载出来,放在操作数栈
把变量b的值2给装载出来,放在操作数栈
在这里插入图片描述
iadd:执行int类型的加法
即从操作数栈中依次弹出栈顶元素相加,最终生成的结果压回操作数栈 a+b

最后 ireturn:从当前方法返回int
从操作数栈中弹出3
即对应 return 3

二、main方法

在这里插入图片描述

代码 Test test = new Test()

new:创建一个对象
我们对比上面的 int a 可以知道,new出来的test 也是一个局部变量,它被存放在main方法对应的栈帧内存区的局部变量表中,
但在jvm底层,对象创建之后放在堆中,
这样我们就可以发现栈和堆之间的一个联系。
那么,这两个东西真的就是一样的嘛?
其实,局部变量表中存放的是堆中对象对应的内存地址,即可以理解为它存放一个指向堆中对象的指针。
在这里插入图片描述
到这里,我们就可以通过字节码在jvm底层结构理解整个Java代码的执行过程。
最后还有一个问题

在这里插入图片描述在这里插入图片描述
在执行main方法时,会跳出去转到computer方法中,在执行完computer方法后,它会再回到main方法中,但是,它回到哪了呢?
方法出口就记录着返回的位置。
同样,程序计数器?
在这里插入图片描述
它记录着程序执行的位置,即行数
设想,在Java代码执行时,经常会有多个线程。学过操作系统的就知道,cpu在运行时,经常会发生线程被抢占,被执行的线程挂起。那么,这个线程被挂起之后,它重新运行时,从哪开始呢?
程序计数器就解决了这个问题。

发布了45 篇原创文章 · 获赞 14 · 访问量 2465

猜你喜欢

转载自blog.csdn.net/qq_44357371/article/details/104059180