贝利信息

在Java里堆和栈有什么区别_Java内存区域对比说明

日期:2026-01-13 00:00 / 作者:P粉602998670
Java中对象存堆、变量和调用帧存栈;堆线程共享需防并发问题,栈线程私有天然安全;堆溢出因内存泄漏,栈溢出多因深度递归;字符串字面量入常量池(堆内),new创建在堆;栈快于堆但性能瓶颈常在GC与引用关系。

堆存对象,栈存变量和调用帧

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

堆溢出 vs 栈溢出:错误现象和排查方向完全不同

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

字符串创建方式决定它在堆还是常量池

字符串是唯一一个“写法不同、内存位置可能不同”的典型:

String a = "hello";        // 字符串字面量 → 先查字符串常量池(堆内),命中则复用,否则新建并入池
String b = new String("hello"); // 强制在堆中新建对象,即使池里已有"hello"
System.out.println(a == b); // false(引用不同)
System.out.println(a.equals(b)); // true(内容相同)

别把“栈快堆慢”当教条,关键看访问模式

栈确实比堆快,因为它是连续内存 + LIFO + 无GC开销;但实际性能瓶颈往往不在这里。

堆和栈的边界在代码里是清晰的,但它们的交互(比如栈上引用指向堆对象)才是多数内存问题真正的藏身之处——漏掉一个引用,对象就永远无法被回收。