jvm是java运行环境,平时开发一般不会涉及到这个。只有在jvm性能调优、内存溢出\栈溢出的时候去jvm查看问题会用到,当然也是面试常问的。今天主要讲一下jvm中的虚拟栈的原理。
以下是jvm内存模型:
![jvm内存模型](https://img-blog.csdnimg.cn/2021071815501741.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxOTE0Ng==,size_16,color_FFFFFF,t_70#pic_center)我们知道平时我们写的.java文件只有经过编译生成.class文件(字节码文件)才能够运行。.而字节码经过类加载器,会将类的信息加载到jvm内存中。类的信息会放在方法区中。jvm内存中,堆用于存储实例对象信息,方法区用于存储常量和类信息。程序计数器用于存储程序下一条要执行的指令地址。而虚拟机栈和本地方法栈,用于存储程序方法运行时的一些变量和操作数,协助执行引擎执完成程序中加减乘除、方法调用等过程。虚拟机栈中存储栈帧,对栈帧的操作是符合栈的特点,先近后出。如下图是栈帧结构:
![栈帧结构](https://img-blog.csdnimg.cn/20210718160820551.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIxOTE0Ng==,size_16,color_FFFFFF,t_70#pic_center)栈帧主要分为局部变量表、操作数栈、动态链接、方法返回地址。
- 局部变量表中存储方法中的变量,分为基本数据数据类型和对象引用,即该变量的对象实例在堆中的地址。局部变量中以槽(32位)为最小存储单位,。double和float类型要两个槽进行存储。而其他用一个槽存储即可。对象也是用32存储其地址。局部变量表编译期间就能确定所需大小,因为方法中的变量是确定的。
- 操作数栈,用于辅助变量计算的栈。就相当于我们平常实现加减乘除运算时所构建的栈结构。
- 动态链接,每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接(为了加速寻找最后调用的方法,这边也有一张表用于存储调用哪个类的方法。)。只有对于虚方法才是动态链接,而对于非虚方法,在编译期间就能确定。
- 方法返回地址。正常返回情况下,记录该方法调用后要执行的指令地址。异常返回有专门的异常处理表。