贝利信息

在Java里堆和栈有什么区别_Java内存区域划分解析

日期:2026-01-21 00:00 / 作者:P粉602998670
堆存对象、栈存变量和调用痕迹;堆共享导致线程不安全,栈私有天然安全;StackOverflowError源于栈溢出,OutOfMemoryError源于堆耗尽;字符串常量池在JDK7+后移入堆中。

堆里存对象,栈里存变量和调用痕迹

Java中所有 new 出来的对象(包括数组、String 实例、自定义类实例)都落在堆中;而方法内的局部变量(如 int i = 10String s)、参数、返回地址这些,全在栈里。注意:s 是引用变量,它自己在栈上,但它指向的字符串对象可能在堆(new String("abc"))或字符串常量池("abc",JDK7+ 后常量池也挪到堆里了)。

堆共享、栈私有:线程安全的关键分水岭

堆是所有线程共用的——多个线程能同时读写同一个对象,所以要小心并发修改引发的 ConcurrentModificationException 或数据不一致;栈是线程私有的——每个线程有自己的一套栈帧,互不干扰,天然线程安全。

StackOverflowError 和 OutOfMemoryError 完全是两回事

StackOverflowErrorOutOfMemoryError: Java heap space 看似都是“内存不够”,但成因和解法毫无交集。

别被“栈快堆慢”带偏,真正瓶颈往往不在这里

栈确实比堆快,因为它是连续内存 + LIFO + 无 GC 开销;但实际性能瓶颈往往不在访问速度,而在引用关系复杂度、GC 频率或对象生命周期管理不当。

堆和栈的边界在 JDK7+ 后变得更模糊(比如字符串常量池进了堆),但“谁管生命周期、谁管共享性、谁触发哪类错误”这三条逻辑线始终清晰。最容易被忽略的是:**栈溢出不是堆不够,堆溢出也不是栈太小;改错参数只会让问题更难排查。**