主题切换
Java堆(Heap)
一、基础定义
- 线程共享:JVM中唯一一块所有线程共享的运行时内存区域;
- 存储内容:所有Java对象实例、数组全部在堆中分配;
- OOM风险:堆内存空间耗尽且无法扩容时,抛出
java.lang.OutOfMemoryError: Java heap space; - GC核心区域:垃圾回收器主要管理的内存区域。
二、堆内存分区结构
堆分为两大块:年轻代(Young Generation) + 老年代(Old Generation)
1. 年轻代 Young
比例默认 Eden : S0 : S1 = 8 : 1 : 1
- Eden区:绝大多数新创建对象的存放位置;Eden占年轻代80%;
- Survivor0(S0)、Survivor1(S1):两块大小完全相等的存活区,同一时间只有一块处于使用状态。 对象流转规则:
- 新建对象放入Eden;
- Eden满触发Minor GC,存活对象复制到空闲Survivor;
- 反复GC后对象年龄到达阈值(默认15),晋升到老年代。
2. 老年代 Old
存放长期存活、生命周期长的对象:
- 多次Minor GC后存活、年龄达标晋升的对象;
- 大对象(超大数组/实例)直接分配到老年代,避免大量复制开销; 老年代空间不足触发Full GC,回收整个堆内存。
三、JDK7 与 JDK8 方法区(永久代/元空间)核心区别
JDK7:永久代 PermGen
- 位置:堆内存内部,属于堆的一部分;
- 存储:类元信息、静态变量、常量池、字节码;
- 缺陷:永久代固定大小,大量动态加载类极易发生永久代OOM。
JDK8:元空间 Metaspace
- 位置:移至操作系统本地内存(堆外),不再占用堆空间;
- 存储:原永久代全部数据迁移至元空间;
- 优势:默认无固定上限,受操作系统物理内存限制,大幅减少类加载导致的OOM。
四、完整总结(面试背诵版)
- Java堆是线程共享内存,存放全部对象与数组,内存耗尽抛出堆OOM;
- 堆分为年轻代、老年代:年轻代Eden+两个等量Survivor,存放新生短期对象;老年代存放长期存活老对象;
- JDK7存在堆内永久代,易类加载OOM;JDK8移除永久代,改用堆外本地内存元空间,规避永久代溢出问题。
五、面试简答
问:详细介绍Java堆?
答: 堆是JVM线程共享的内存区域,所有对象实例、数组都在堆分配,堆空间不足会抛出堆内存OOM。 堆分为年轻代和老年代:年轻代分为Eden、S0、S1三块,比例8:1:1,新对象先放Eden,Minor GC存活对象进入Survivor,年龄达标后晋升老年代;老年代存放生命周期长的对象。 JDK7堆内有永久代存储类信息,容易OOM;JDK8把永久代移除,改为操作系统本地内存的元空间,解决类加载溢出问题。