JVM学习笔记之栈区

凯哥java 凯哥java

JVM学习笔记之栈区

本文主要内容:

栈是什么?栈帧又是什么?在JVM中,main方法调用say方法后,是怎么运行的?本文将详细讲解栈。希望大家学了之后,对栈有更深的了解。

心法:在JVM中,栈管运行,堆管存储。

栈数据结构特点:先进后出。生活中常见的case就是弹夹。最后一个压进弹夹的子弹,最先出弹夹。

Stack栈: 栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,它的生命周期跟随线程的生命周期,线程结束,栈内存也就被释放了。对于栈来说,不存在垃圾回收问题,只要是线程一结束,该栈就over了。生命周期和线程一直的,是线程私有的。

8中基本类型的变量+对象的引用变量+实例方法都是在函数的栈内存中分配的。

栈中存储的是什么?

在了解栈之前,先来了解另一个概念:栈帧。

栈帧

栈帧(Stack Frame):用于支持虚拟机进行方法调用和方法执行的数据结构。它是虚拟机运行时数据区中的虚拟机栈的栈元素。

栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每个方法从调用开始至执行完成的过程,都对应这一个栈帧在虚拟机栈里面从入栈到出栈的过程。

额,什么叭叭叭的,说的什么意思呢?简单如下:

栈帧中主要保存3类数据:

本地变量(Local variables):输入参数和输出参数以及方法内的变量;

如上图中的 int x,int y就是输入参数

Int result就是输出参数。

其中的X、Y、result都是方法内的变量

栈操作(Operand Stack):记录出栈、入栈的操作;

栈帧数据(fram Date):包括类文件、方法等等。

栈运行的原理:

栈中的数据都是以栈帧的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期,数据的数据集。

当一个方法A被调用的时候,就产生了一个栈帧F1,并被压到栈中;

A方法调用了B方法,于是产生了栈帧F2也被压入栈中;

B方法又调用了C方法,于是产生栈帧F3,也被压入到栈中;

依次类推。

当执行完毕后,先弹出F3栈帧,在弹出F2栈帧,在弹出F1栈帧。依次类推。

遵循”先进后出/后进先出”的原则。

代码演示:

写个main函数,在main方法中,调用say方法。然后查看输出结果。

编辑 运行结果:

当程序运行到3行的时候,调用了主线程main函数,这个时候产生了栈帧F1,被压入栈,代码继续向下走;

当代码执行到第5行的时候,调用了say方法,这个时候产生了栈帧F2,发现后面还有代码需要执行,F2就被压入栈;

当执行第10行的时候,say方法调用了showCode方法,这个时候就产生了F3。进入方法showCode方法后,后面还有代码,F3压栈,继续执行。

当执行到第17行的时候,发现没有需要执行的了。F3就从栈里面被弹出栈了;

接着回到say方法里面,继续执行,程序走到第12行的时候,发现say方法执行完成了,于是F2就被弹出栈了;

程序回到main方法中,也就是该执行第6行了,执行完第6行,当到底7行的时候,发现主函数也执行了了,于是F1就被弹出栈了;

整个线程执行完成,栈区被清空。程序结束。如下图:

一个线程中的方法调用链可能会很长,很多方法都同时处于执行状态。对于执行引擎来说,在活动线程中(争抢到CPU执行权的),只有位于栈顶的栈帧才是有效的,成为当前栈帧(Current Stack Frame),与这个栈帧相关联的方法称为当前方法(Current Method)。执行引擎运行的所有字节码指令都是只针对于当前栈帧进行操作的。

栈帧概念模型如下图:

需要说明的是:每个方法执行的同时都会创建一个栈帧,用于存放局部变量表、操作数栈、动态连接、方法返回等等数据。每个方法从被调用至执行完成的过程,就对应着一个栈帧在虚拟机中入栈和出栈的过程。栈的大小和具体JVM的实现有关,通常在256K~756K之间,约等于1Mb左右。

栈+堆+方法区的交互关系

HotSpot是使用指针的方法来访问对象的:

Java堆中会存放访问类元数据的地址,reference存放的就直接是对象的地址。