栈管运行,堆管存储
栈(stack)是什么 -----------------------------------------------------------------线程私有
栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程结束该栈就Over,生命周期和线程一致,是线程私有的。
基本类型的变量 和对象的引用变量都是在函数的栈内存中分配。
栈运行的原理 ------------------------------------------------------------------------栈帧
栈中的数据都是以栈帧(Stack Frame) 的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法 (Method)和运行期数据的数据集,
栈帧(stack frame)是计算机中用于存储函数调用信息的一种数据结构。它在函数被调用时被创建,在函数执行完毕后被销毁。
栈帧是用于存储函数调用信息的数据结构,它在函数被调用时被创建,在函数执行完毕后被销毁。栈帧包含了方法(函数)的局部变量、方法的参数、方法的返回地址和方法的返回值等信息。栈帧的创建和销毁是由程序的执行流程自动完成的,它们的管理是由编译器和操作系统来完成的。栈帧的存在使得程序可以方便地进行函数调用和返回操作。
当一个方法A被调用时就产生了一个栈帧F1, 并被压入到栈中
A方法又调用了B 方法,先是产生栈帧F2也被压入栈
B方法又调用了C方法,于是产生栈帧F3也被压入栈
..... 执行完毕后,
先弹出F3栈帧
再弹出F2栈帧
再弹出F1栈......
遵循“先进后出”或者“后进先出”原则。
栈结构如图-------------------------------------------------------------------基本类型的变量 和对象的引用变量
(1)局部变量表
局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。
(2)操作数栈
操作数栈也是 被组织成一个以 字节 为 单位 的 数组 ,通过标准的栈操作—压栈和出栈—来访问的。比如,如果某个指令把一个值压入到操作数栈中,稍后另一个指令就可以弹出这个值来使用。 虚拟机把操作数栈作为它的工作区——大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。比如,iadd指令就要从操作数栈中弹出两个整数,执行加法运算,其结果又压回到操作数栈中,看看下面的示例,它演示了虚拟机是如何把两个int类型的局部变量相加,再把结果保存到第三个局部变量的:
1. begin 2. iload_0 // push the int in local variable 0 onto the stack 3. iload_1 // push the int in local variable 1 onto the stack 4. iadd // pop two ints, add them, push result 5. istore_2 // pop int, store into local variable 2 6. end
在这个字节码序列里,前两个指令iload_0和iload_1将存储在局部变量中索引为0和1的整数压入操作数栈中,其后iadd指令从操作数栈中弹出那两个整数相加,再将结果压入操作数栈。第四条指令istore_2则从操作数栈中弹出结果,并把它存储到局部变量区索引为2的位置。
(3)动态连接
每个栈帧都包含一个指向运行时常量池中该栈帧所属性方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。在 Class 文件的常量池中存有大量的 符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化 称为静态解析。另外一部分将在每一次的运行期期间转化为直接引用,这部分称为动态连接
(4)方法返回地址
当一个方法被执行后,有两种方式退出这个方法:正常退出和异常退出。
无论采用何种方式退出,在方法退出之前,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上 层方法的执行状态。一般来说,方法正常退出时,调用者 PC 计数器的值就可以作为返回地址,栈帧中很可能会保存这个计数器值。而方法异常退出时,返回地址是 要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。
方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值 (如果有的话) 压入调用栈帧的操作数栈中,调用 PC 计数器的值以指向方法调用指令后面的一条指令等。
栈内存溢出
Exception in thread "main" java.lang.StackOverflowError
异常产生的原因:栈帧压栈的时候,超出了栈的深度。
------------------------------------------------------------------------------------------------------------------------------
内存溢出(Memory Overflow)是指程序在运行过程中申请的内存超过了系统所能提供的内存空间。当程序申请的内存超出系统限制时,会导致程序崩溃或异常终止。
------------------------------------------------------------------申请的内存超过了系统所能提供的内存空间
内存泄露(Memory Leak)是指程序在运行过程中申请的内存没有被正确释放,导致这部分内存无法再被程序使用,从而造成内存资源的浪费。内存泄露会导致系统的可用内存逐渐减少,最终可能导致系统性能下降甚至崩溃。---------------------不正确释放对象导致内存资源的浪费导致内存泄露