JVM整体结构及内存模型

张开发
2026/4/19 7:48:58 15 分钟阅读

分享文章

JVM整体结构及内存模型
JVM内存模型定义了Java程序运行时数据的存储区域共分为六大区域堆、方法区元空间、虚拟机栈、本地方法栈、程序计数器、直接内存。其中堆和方法区线程共享其他为线程私有。一、运行时数据区域概览二、各区域详细说明1. 堆内存Heap堆内存Heap是 JVM 管理的最大的一块内存区域被所有线程共享专门用于存储对象实例和数组。属性说明存储内容对象实例、数组线程共享是生命周期JVM启动时创建JVM关闭时销毁GC管理是主要回收区域堆的分代结构:2. 方法区Method Area/ 元空间Metaspace元空间Metaspace是 JDK 8 开始用来存储类元数据如类名、方法信息、字段信息、常量池等的内存区域它使用本地内存Native Memory而非虚拟机内部内存从而避免了经典的 OutOfMemoryError: PermGen space 问题。属性说明存储内容类元信息、静态变量、常量池、方法字节码线程共享是位置变化Java 7永久代Java 8元空间本地内存GC管理部分常量池回收、类卸载3. 栈内存Stack栈JVM Stack是线程私有的内存空间而栈帧Stack Frame是栈中的元素/单元。可以理解为栈是载体容器栈帧是放入其中的具体内容。属性说明存储内容栈帧局部变量表、操作数栈、动态链接、方法出口线程私有是生命周期与线程相同异常StackOverflowError、OutOfMemoryError生成时机栈帧在每次调用方法时创建压入当前线程的栈顶。销毁时机方法正常返回或异常结束时销毁从栈顶弹出。每个栈帧包含局部变量表存储方法参数和局部变量操作数栈存放计算过程中的中间结果动态链接指向运行时常量池的符号引用方法出口方法执行后返回的地址4. 程序计数器PC Register程序计数器是一块很小的内存区域每个线程私有用于存储当前线程所执行的字节码的行号指示器即下一条要执行的指令地址。属性说明存储内容当前线程执行的字节码行号线程私有是唯一无OOM区域不会出现OutOfMemoryError5. 本地方法栈Native Method Stack本地方法栈是一块线程私有的内存区域专门用于支持 Native 方法如使用 C/C 编写的底层方法的执行为这些方法提供服务如局部变量存储、操作数栈等。属性说明存储内容本地方法Native方法的执行信息线程私有是作用为JVM执行Native方法服务6. 直接内存Direct Memory直接内存是 NIONew I/O中引入的一块特殊内存区域它不在 JVM 堆内管理而是由操作系统直接分配和管理的本地内存用于提高 I/O 操作的性能避免数据在 JVM 堆和本地内存之间来回拷贝。属性说明存储内容NIO直接缓冲区分配方式通过ByteBuffer.allocateDirect()特点不受堆大小限制但受物理内存限制三、内存区域对比区域线程共享存储内容GC回收OOM风险堆是对象实例是高方法区/元空间是类元数据、静态变量部分中虚拟机栈否局部变量、操作数栈否StackOverflow程序计数器否字节码行号否无本地方法栈否Native方法信息否中直接内存否NIO缓冲区否中四、常见问题1. 内存溢出场景异常产生区域原因OutOfMemoryError: Java heap space堆对象过多GC无法回收OutOfMemoryError: Metaspace元空间加载类过多StackOverflowError栈递归过深OutOfMemoryError: Direct buffer直接内存NIO缓冲区未释放2. 参数配置# 堆内存 -Xms2g # 初始堆大小 -Xmx2g # 最大堆大小 -Xmn512m # 年轻代大小 # 元空间Java 8 -XX:MetaspaceSize256m # 初始元空间大小 -XX:MaxMetaspaceSize256m # 最大元空间大小 # 栈内存 -Xss1m # 每个线程栈大小五、核心要点总结堆和方法区是线程共享的存在线程安全问题栈和PC寄存器是线程私有的天然线程安全Java 8将永久代改为元空间使用本地内存避免OOM程序计数器是唯一不会OOM的内存区域栈内存每个方法调用都会创建栈帧方法结束自动释放

更多文章