栈是什么
在线程创建时创建,栈的生命周期跟随线程的生命期,线程结束栈就释放
栈中的数据以栈帧的形式存在,一个栈帧入栈可以看作为是一个方法的调用
栈帧中包含四个组件:
局部变量表,操作数栈,动态链接,返回地址
1.局部变量表
一组变量值存储空间,存放方法参数和局部变量
2.操作数栈
栈中执行运算的地方
可对class文件 使用javap -c指令去反编译字节码文件
举例:
对其进行javap -c指令后,可看到
我们对其进行一个解析:
- 将常量1压栈
- 保存1到局部变量表第二个位置
- 将常量2压栈
- 保存到第三个位置
- 从局部变量表加载局部变量表第二个位置到操作数栈
- 从局部变量表加载局部变量表第三个位置到操作数栈
- 到操作数栈执行相加操作
- 保存到局部变量表第四个位置
3.动态连接
在此之前我们先了解 ==类加载阶段的解析阶段 ==:
把类中的符号引用转化为直接引用。解释一下符号引用和直接引用。比如在方法A中使用方法B,这里的B()就是符号引用,初学java时我们都是知道这是java的引用,以为B指向B方法的内存地址,但是这是不完整的,这里的B只是一个符号引用,它对于方法的调用没有太多的实际意义,可以这么认为,他就是给程序员看的一个标志,让程序员知道,这个方法可以这么调用,但是B方法实际调用时是通过一个指针指向B方法的内存地址,这个指针才是真正负责方法调用,他就是直接引用。
这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化 称为静态解析。另外一部分将在每一次的运行期期间转化为直接引用,这部分称为动态连接
4.方法返回地址
一个栈是一个线程,是一行一行,一个方法一个方法运行的。当前方法运行结束后,要恢复上个调用方法的运行
方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值 (如果有的话) 压入调用栈帧的操作数栈中,调用 PC 计数器的值以指向方法调用指令后面的一条指令等。
5.栈内存溢出
Exception in thread “main” java.lang.StackOverflowError
异常产生的原因:栈帧压栈的时候,超出了栈的深度。
可能原因:无限制的方法递归
举例:编写一个无限递归的方法
运行结果: