深入理解栈
-
栈又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把 另一端称为栈底。其特性是先进后出。
-
栈是线程私有的,生命周期跟线程相同,当创建一个线程时,同时会创建一个栈,栈的大小和深度都是固定的。
-
方法参数列表中的变量,方法体中的基本数据类型的变量和引用数据类型的引用都存放在栈中,成员变量和对象本身不存放在栈中。运行时,成员函数的局部变量引用也存放在栈中。
-
栈的变量随着变量作用域的结束而释放,不需要jvm垃圾回收机制回收。
-
栈不是全局共享的,每个线程创建一个栈,该线程只能访问其对应的栈数据
-
栈内存的大小是在编译期就确定了的。
栈帧:
- **一个栈中可以有多个栈帧,栈帧随着方法的调用而创建,随着方法的结束而消亡。**该栈帧中存储该方法中的变量,原则上各个栈帧之间的数据是不能共享的,但是在方法间调用时,jvm会将一方法的返回值赋值给调用它的栈帧中。每一个方法调用,就是一个压栈的过程,每个方法的结束就是一个弹栈的过程。压栈都将会将该栈帧置于栈顶,每个栈不会同时操作多个栈帧,只会操作栈顶,当栈顶操作结束时,会将该栈帧弹出,同时会释放该栈帧内存,其下一个栈帧将变为栈顶。栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。
- 栈帧的组成部分分为局部变量表、操作数栈、动态连接、方法返回地址。
栈的优点:
-
栈帧内存数据共享:栈帧之间数据不能共享,但是同一个栈帧内的数据是可以共享的,这样设计是为了减小内存消耗,例如:int a = 1, int b= 1时,**前面定义了a=1,a和1都在栈内存内,如果再定义一个b=1,此时将b放入栈内存,然后查找栈内存中是否有1,如果有则b指向1。**如果再给b赋值2,则在栈内存中查找是否有2,如果没有就在栈内存中放一个2,然后b指向2。也就是如果常量在栈内存中,就将变量指向该常量,如果没有就在该栈内存增加一个该常量,并将变量指向该常量。
-
存取速度比堆要快,仅次于寄存器。速度快之一是栈在编译器就申请好了内存空间,所以在运行时不需要申请内存大小,节约了时间,其二是栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。其三是访问时间,访问堆的一个具体单元,需要两次访问内存,第一次得取得指针,第二次才是真正得数据,而栈只需访问一次。
栈的缺点:
- 存在栈的数据大小和生存期必须是确定的,缺乏灵活性。当栈在运行执行程序时,发现栈内存不够,不会动态的去申请内存,以至于导致程序报错,所以灵活性较差。
1、栈里面存放什么
栈:8大基本类型 + 对象的引用 + 实例的方法
2、栈运行原理
栈帧
栈满了:StackOverflowError
3、栈堆方法区的交互关系
深入理解堆
Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行,堆内存**逻辑上(注意是逻辑上)**分为三部分:
新生区、养老区、永久区。
1、堆里面存放什么
类加载器读取了类文件后,一般会把什么东西放在堆中? 类,方法,常量,变量,保存我们所有引用类型的真实对象
堆内存中逻辑上还要细分为三个区域:
- 新生区(伊甸园区)young/new
- 养老区 old
- 永久区(Java 8 此区域改叫元空间,后面介绍) perm
堆内存中物理上只有新生区和养老区,其内存比例为1:2。