Java为什么要分堆和栈

1.生命周期不一样

栈:跟方法走

堆:生命周期不确定

  • 栈里的数据 :跟着方法走。方法调用 → 压入栈帧;方法执行完毕 → 栈帧直接弹出销毁。生命周期很短,不需要垃圾回收。 存:局部变量、基本类型、对象引用地址(不是对象本身)
  • 堆里的对象:生命周期不确定。对象创建后,可能跨很多方法、跨线程使用,方法跑完对象不一定没用。什么时候没人引用了,才由 GC 回收。

2.访问速度差距大

栈:分配和回收极快,内存连续,分配方式简单(移动栈指针),接近 CPU 寄存器速度。
堆:分配慢很多,需要在一大片空闲内存里找一块合适空间,还要维护空闲链表、GC 标记整理。

3.隔离并发,天然保证线程安全

  • 栈:线程私有,每个线程有自己独立栈,不存在多线程同时修改同一个栈内局部变量,天然无竞争。
  • 堆:线程共享,所有线程都能访问里面的对象,需要同步锁保证安全。

4. 内存大小特性不同

  • 栈空间很小(一般几 MB),适合存放少量局部变量、引用(栈深度有限,调用太深会StackOverflowError)
  • 堆空间很大(G 级别),适合存放数量不确定、大小不确定的对象、集合

补充一个高频误区

基本类型一定在栈,对象一定在堆❌

局部变量里的基本类型在栈;成员变量跟着对象走,对象在堆,成员变量就在堆。✅

还有 JDK 逃逸分析:如果对象不逃出方法,JIT 可以做栈上分配,对象直接分配在栈,避免 GC 开销,这是优化,不是默认行为。

即:

逃逸分析 = JIT 检查:这个 new 出来的对象,会不会跑到方法外面被别的代码拿到。如果它 "逃不出去",就叫【不逃逸】,JIT 可以优化,不在堆上创建对象,改在栈上分配。

局部变量:写在方法内 / 代码块({})里面的变量,只在当前方法生效

基本类型 :Java 原生基础类型,不是对象,没有 new,存的就是真实值 8 个: byte、short、int、long float、double char boolean

区分:

  • 基本类型:存值本身
  • 引用类型(类、数组、String、集合等):存对象地址

成员变量:写在类里面、方法外面的变量,属于类 / 对象(实例变量 + 静态变量)

例如代码:

java 复制代码
public void test() {
    User u = new User(); 
    u.age = 18;
    System.out.println(u.age);
}
逃逸分析判断:这个对象有没有逃逸?

逃逸 = 对象的引用流出当前方法,外面别的代码 / 别的线程可以拿到这个对象

相关推荐
杨凯凡32 分钟前
Spring Boot 缓存一致性怎么保证?@Cacheable、@CacheEvict 与事务提交时机实战
java·spring boot·spring cache·后端开发·缓存一致性
小小晓.1 小时前
Qt 对话框、QLineEdit 与布局管理实战详解
开发语言·qt
炸薯条!2 小时前
博客系统测试报告
开发语言·lua
Evand J2 小时前
【MATLAB例程12】永磁同步电机基于增广无迹卡尔曼滤波的未知负载转矩在线观测
开发语言·matlab
Rain的Java大神之路2 小时前
国家数据集团校招、社招都开了:总部雄安,这些技术岗值得认真看看
java·后端·面试
吴名氏.2 小时前
Java转AI Agent教程(第九周)错误矩阵
java·人工智能·矩阵·ai agent
文丑颜不良啊2 小时前
LeetCode1901~1920题目解析
java·leetcode
tealcwu2 小时前
【Unity基础】为什么游戏需要物理按键映射?从 Unity Input Manager 到跨引擎输入设计
java·游戏·unity