堆(所有线程共享)
JVM中最大的一块内存区域,存储所有的对象实例和数组。
堆内存由垃圾回收器管理,垃圾回收器会自动释放不再被引用的对象占用的内存。
栈(每个线程独立)
每个线程都有自己的栈内存。栈用于存储局部变量、方法参数、返回地址、方法调用链等。
栈具有快速分配和释放的特点。每次方法调用都会在栈中创建一个新的栈帧,方法执行完毕后会呗自动销毁。
什么是栈帧:
栈帧存储方法的局部变量,包括参数和方法内部声明的变量。
为什么需要栈帧,而不是直接将数据存储到线程的栈中:
- 方法调用的递归和嵌套
方法递归的时候,每次调用都需要独立维护自己的执行环境和状态。这包括 局部变量、参数和计算得到的结果。每个栈帧单独存储这些信息,确保各个方法调用不干扰。
- 便于管理方法的调用和返回、
栈帧是的方法的调用和返回更加的简单。每个栈帧包含方法返回地址,当方法执行完毕时,JVM可以通过栈帧信息找到返回地址并恢复调用方法的执行。
- 错误处理和调试
栈帧在处理异常中也起到重要作用。当方法抛出异常的时候,栈帧信息用于构建异常堆栈跟踪(也就是找到代码错误位置)。
小结
栈帧的设计是为了方法间的独立,防止方法间变量冲突、方法返回地址混乱等问题。
方法区
方法区存储已加载类信息、常量池、静态变量、即使编译后的代码等。
方法区也是堆的一部分,所以方法区也是线程间共享的内存。
为什么方法区是共享的?
- 类和元数据的统一管理
当一个类被加载时,JVM在方法区创建这个类的元数据结构。这个结构对于所有线程是共享的,因为同一个类只需要在内存中有一个表示。
- 常量池共享
常量池中的字面量和符号引用需要被所有线程访问,特别是在类的加载和连接阶段,以及在运行时常量池解析时。
- 静态变量共享
静态变量是类级别的变量,所有线程都应当能访问和修改这些变量。
什么是字面量?
字面量是在编译的时候就知道的变量,如字符串常量、整数常量等(存在类中的变量)