java内存管理的核心是堆与栈:堆为线程共享、存放对象实例并由gc管理;栈为线程私有、存放方法调用的栈帧及局部变量,方法结束即自动释放。

Java 内存管理的核心,是理解 JVM 如何把一块物理内存划分为不同职责的区域,并按规则分配和回收。堆和栈不是“两个内存块”,而是运行时数据区中功能明确、生命周期迥异的两大关键部分——一个管对象,一个管方法执行。
堆:所有对象的统一存放地
堆是 JVM 中最大、线程共享的内存区域,所有 new 出来的对象实例、数组、字符串常量池(JDK 7+)、静态变量(JDK 7 起移入)都存在这里。它不归某个线程独有,所以必须考虑并发安全,GC 也主要在这里工作。
- 分代设计:新生代(Eden + 两个 Survivor)存短期对象;老年代存长期存活对象。这种划分让垃圾回收更高效——大部分对象朝生暮死,只在新生代清理即可。
- 分配方式:对象优先在 Eden 区分配;大对象可能直接进老年代(避免频繁复制);长期存活对象经过多次 GC 后晋升到老年代。
- 异常提示:当堆空间不足且无法扩展(如 -Xmx 设限)或 GC 后仍无法腾出足够空间,就会抛出 OutOfMemoryError: Java heap space。
栈:每个线程专属的方法执行空间
Java 虚拟机栈是线程私有的,生命周期与线程一致。它不存对象本身,而是为每个方法调用创建一个栈帧(Stack Frame),用来支撑方法执行过程。
- 栈帧内容:包括局部变量表(存基本类型、对象引用、returnAddress)、操作数栈(临时计算用,比如 a+b 的中间结果压栈再弹出)、动态链接(指向运行时常量池的方法引用)、方法返回地址等。
- 分配时机:方法调用时立即分配,大小在编译期就确定,运行时不扩容也不缩容;方法结束即出栈,内存自动释放,无需 GC。
- 异常提示:StackOverflowError 多见于无限递归或超深调用链(栈深度超 -Xss 限制);OutOfMemoryError 则发生在栈尝试动态扩展但系统内存已耗尽时。
堆与栈的关键区别,不只是位置
很多人记成“栈放基本类型,堆放对象”,这容易误导。真正区别在于:栈管理的是方法的执行上下文,堆管理的是对象的生命周期。一个 int 变量可能在栈上(局部变量),也可能在堆上(作为对象字段);一个 String 引用在栈上,它指向的字符数组却一定在堆上。
- 线程视角:栈是“每人一间房”,互不干扰;堆是“公共大厅”,所有人共用,需同步协调。
- 内存回收:栈内存随方法退出自动清理;堆内存靠 GC 判断可达性后回收,存在延迟和不确定性。
- 配置参数:堆大小由 -Xms / -Xmx 控制;栈大小由 -Xss 控制(默认一般 1MB 左右)。
其他配套区域,协同工作
堆和栈虽是主角,但离不开其他区域配合:
- 程序计数器:每个线程一个,记录当前执行到哪条字节码指令,是唯一不会 OOM 的区域。
- 方法区 / 元空间:存类结构、常量池、静态变量(JDK 8+ 元空间用本地内存,不再受 PermSize 限制)。
- 本地方法栈:类似虚拟机栈,但服务 native 方法(如 JNI 调用)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











