Java为什么要分堆和栈 1.生命周期不一样栈跟方法走堆生命周期不确定栈里的数据跟着方法走。方法调用 → 压入栈帧方法执行完毕 → 栈帧直接弹出销毁。生命周期很短不需要垃圾回收。 存局部变量、基本类型、对象引用地址不是对象本身堆里的对象生命周期不确定。对象创建后可能跨很多方法、跨线程使用方法跑完对象不一定没用。什么时候没人引用了才由 GC 回收。2.访问速度差距大栈分配和回收极快内存连续分配方式简单移动栈指针接近 CPU 寄存器速度。堆分配慢很多需要在一大片空闲内存里找一块合适空间还要维护空闲链表、GC 标记整理。3.隔离并发天然保证线程安全栈线程私有每个线程有自己独立栈不存在多线程同时修改同一个栈内局部变量天然无竞争。堆线程共享所有线程都能访问里面的对象需要同步锁保证安全。4. 内存大小特性不同栈空间很小一般几 MB适合存放少量局部变量、引用栈深度有限调用太深会StackOverflowError堆空间很大G 级别适合存放数量不确定、大小不确定的对象、集合补充一个高频误区基本类型一定在栈对象一定在堆❌局部变量里的基本类型在栈成员变量跟着对象走对象在堆成员变量就在堆。✅还有 JDK 逃逸分析如果对象不逃出方法JIT 可以做栈上分配对象直接分配在栈避免 GC 开销这是优化不是默认行为。即逃逸分析 JIT 检查这个 new 出来的对象会不会跑到方法外面被别的代码拿到。如果它 “逃不出去”就叫【不逃逸】JIT 可以优化不在堆上创建对象改在栈上分配。局部变量写在方法内 / 代码块{}里面的变量只在当前方法生效基本类型Java 原生基础类型不是对象没有 new存的就是真实值 8 个byte、short、int、longfloat、doublecharboolean区分基本类型存值本身引用类型类、数组、String、集合等存对象地址成员变量写在类里面、方法外面的变量属于类 / 对象实例变量 静态变量例如代码public void test() { User u new User(); u.age 18; System.out.println(u.age); }逃逸分析判断这个对象有没有逃逸逃逸 对象的引用流出当前方法外面别的代码 / 别的线程可以拿到这个对象1.2.