1. 堆(Heap)
-
作用:存放所有对象实例及数组,是垃圾回收的主要区域。
-
结构:
-
新生代(Young Generation):
-
Eden区:新创建的对象首先分配在此。
-
Survivor区(From/To):经过Minor GC存活的对象被转移到Survivor区,多次存活后晋升至老年代。
-
-
老年代(Old Generation):长期存活的对象或大对象直接分配在此。
-
-
特点:
-
线程共享,需考虑线程安全问题。
-
通过
-Xms
(初始堆大小)、-Xmx
(最大堆大小)调整内存。 -
垃圾回收:新生代使用复制算法(Minor GC),老年代使用标记-清除/整理算法(Major GC)。
-
2. 栈(Stack)
-
作用:存储方法调用的栈帧,包含局部变量、操作数栈、动态链接和方法出口。
-
结构:
-
局部变量表:存放基本数据类型(
int
,boolean
等)和对象引用(reference
)。 -
操作数栈:执行字节码指令的工作区。
-
动态链接:将符号引用转换为直接引用,支持多态。
-
方法出口:记录方法返回地址。
-
-
特点:
-
线程私有,生命周期与线程一致。
-
栈深度由
-Xss
参数设置,默认1MB(不同JVM实现可能不同)。 -
异常:
StackOverflowError
(栈溢出)、OutOfMemoryError
(扩展失败)。
-
3. 方法区(Method Area)
-
作用:存储类信息、常量、静态变量、即时编译器优化后的代码。
-
演变:
-
JDK ≤7:永久代(PermGen),受JVM内存限制,易出现
OutOfMemoryError: PermGen space
。 -
JDK ≥8:元空间(Metaspace),使用本地内存,通过
-XX:MetaspaceSize
和-XX:MaxMetaspaceSize
调整。
-
-
关键部分:
-
运行时常量池:存放编译期生成的常量(如字面量、符号引用)。
-
字符串常量池(移至堆中):JDK7开始将字符串常量池从方法区移至堆,避免永久代OOM。
-
4. 各区域对比
特性 | 堆(Heap) | 栈(Stack) | 方法区(Method Area) |
---|---|---|---|
存储内容 | 对象实例、数组 | 局部变量、方法调用栈帧 | 类信息、常量、静态变量 |
线程共享性 | 所有线程共享 | 线程私有 | 所有线程共享 |
内存管理 | 垃圾回收管理 | 自动分配/释放(方法结束) | 垃圾回收(类卸载时) |
异常 | OutOfMemoryError | StackOverflowError | OutOfMemoryError (元空间满) |
JVM参数 | -Xms , -Xmx | -Xss | -XX:MetaspaceSize |
6. 实战建议
-
堆内存调优:根据应用负载设置合理的
-Xms
和-Xmx
,避免频繁Full GC。 -
栈深度控制:递归或深调用链时,适当增大
-Xss
防止栈溢出。 -
元空间监控:生产环境设置
-XX:MaxMetaspaceSize
限制元空间,避免耗尽本地内存。
总结:理解堆、栈和方法区的结构与功能,是优化Java应用内存使用、排查内存泄漏和性能问题的关键。结合JVM参数调整和监控工具,可有效提升应用稳定性和效率。