数据结构 [栈]
栈概念
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
——百度百科《栈》
这是一个简易的栈工作图,可以把它理解为手枪的弹夹,每次装弹的时候越先装入的子弹会在弹夹越下面,射击的时候会先射出最后装入的子弹,依此类推,最先装入的子弹最后射出。|第一个进入栈内的数据出栈就是最后一个,总结: 栈始终保持着先进后出,后进先出的原则。
虚拟机栈
概念
1、java程序中每个方法被执行的时候,jvm都会同步创建一个栈帧(可以理解为弹夹中的子弹)用于存储参数、局部变量、动态连接、操作数栈和方法出口等信息,可以理解为每个方法运行时需要的内存。
2、每一个方法被调用直至执行完毕的过程,就会对应着一个栈帧在jvm中完成入栈到出栈的过程。
3、虚拟机栈和程序计数器一样是线程私有的生命周期于线程相同,也可以说虚拟机栈是线程运行时需要的内存空间。
4、每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。
示例
public static void main(String[] args){
test1();
}
private static void test1(){
test2();
}
private static void test2(){
System.out.println("测试栈帧");
}
使用 debug 模式启动,在输出那里打个断点,然后查看控制台可以看到对应的方法名字。
这里时先调用的 test1() ,后调用的 test2() ,栈先进后出,后进先出的原则。test1方法在test2方法下面,最后执行释放时 test2栈帧会先释放 test1栈帧 会后释放。
我们通常写业务代码会调用各种方法,那么会在虚拟机栈中产生许多栈帧,栈帧中又存储着数据,那么到达一定程度时会产生内存溢出的问题。
内存溢出
原因:
1、 栈证过多导致内存溢出
2、 栈证过大导致内存溢出(一般不会出现)
栈帧过多示例
private static int count;
public static void main(String[] args){
try{
method1();
}catch(Throwable e){
e.printStackTrace();
Sytem.out.println(count);
}
}
private static void method1(){
count++;
method1();
}
运行以上代码会报 java.lang.StackOverflowError 栈内存溢出错误。