java堆内存是线程共享的,因其设计目标是让所有线程共同访问对象实例,避免数据不一致;逻辑上分代管理(新生代含eden和两个survivor区)、物理上支持tlab线程私有分配,并可通过逃逸分析优化为栈上分配。

Java堆内存是线程共享的,根本原因在于它的设计目标:让所有线程能共同访问和操作对象实例。对象一旦创建,往往需要被多个线程读写(比如缓存、共享配置、任务队列等),如果每个线程都维护一份堆,不仅浪费内存,更会导致数据不一致、无法协同。因此,JVM在启动时就分配一块统一的堆空间,由所有线程共用——这就像公司共用一个文档服务器,而不是每人一台本地电脑存同一份文件。
不过,“共享”不等于“无隔离”。为兼顾性能与并发安全,堆内部做了精细划分:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
-
逻辑上按代管理(分代模型)
堆被划分为新生代(Young Gen)和老年代(Old Gen):- 新生代又细分为 Eden 区、Survivor0(From)、Survivor1(To)三个子区,比例默认为 8:1:1
- 大多数对象在 Eden 区分配;经历 Minor GC 后幸存的对象,在 Survivor 区之间来回复制,达到一定年龄才晋升到老年代
-
物理上支持线程私有缓存(TLAB)
虽然堆整体共享,但 JVM 会在 Eden 区为每个线程预先划出一小块独占区域,叫 Thread Local Allocation Buffer(TLAB)。- 线程在 TLAB 中分配对象无需加锁,大幅提升小对象分配速度
- TLAB 耗尽后,才会在 Eden 共享区或触发同步分配,甚至可能触发 GC
例外情况:逃逸分析后的栈上分配
若 JIT 编译器判定某个对象的作用域仅限于当前方法且不会被其他线程访问(即“未逃逸”),JVM 可能直接把它分配在虚拟机栈上,跳过堆。但这属于优化手段,不改变“堆是默认且主要的对象存储场所”这一本质。
堆的共享特性也带来实际约束:
- 多线程访问堆中同一对象时,需靠 synchronized、volatile 或 java.util.concurrent 工具保证可见性与原子性
- GC 操作会暂停所有应用线程(Stop-The-World),尤其在老年代回收时影响明显
- 内存泄漏往往表现为堆中对象持续累积,最终触发 OutOfMemoryError
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










