JVM内存结构全景:5大区域详解
引言:为什么要理解JVM内存结构? 当你遇到以下问题时,是否感到困惑: StackOverflowError 和 OutOfMemoryError 有什么区别? 为什么有的对象存储在堆中,有的却在栈中? 静态变量存储在哪里?方法代码又存储在哪里? 为什么多线程之间可以共享对象,却不能共享局部变量? 这些问题的答案,都藏在 JVM内存结构 中。 理解JVM内存结构是深入学习JVM的基础: 性能调优:知道内存如何分配,才能优化内存参数 问题排查:90%的内存问题与内存区域的使用不当相关 代码优化:理解对象存储位置,才能写出高效代码 本文将带你建立JVM内存结构的全景认知,为后续深入学习每个区域打下基础。 JVM内存结构全景图 运行时数据区概览 当Java程序运行时,JVM会将内存划分为不同的数据区域,这些区域统称为 运行时数据区(Runtime Data Area)。 根据《Java虚拟机规范》,JVM运行时数据区包括以下5大区域: ┌─────────────────────────────────────────────────────────┐ │ JVM 运行时数据区 │ ├─────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ 程序计数器 │ │ 程序计数器 │ 线程私有 │ │ │ (PC Register) │ │ (PC Register) │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ 虚拟机栈 │ │ 虚拟机栈 │ 线程私有 │ │ │ (VM Stack) │ │ (VM Stack) │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ 本地方法栈 │ │ 本地方法栈 │ 线程私有 │ │ │ (Native Stack) │ │ (Native Stack) │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ ├─────────────────────────────────────────────────────────┤ │ │ │ ┌───────────────────────┐ │ │ │ 堆内存 │ 线程共享 │ │ │ (Heap) │ │ │ │ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ 新生代 (Young) │ │ │ │ │ │ Eden + S0 + S1 │ │ │ │ │ └─────────────────┘ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ 老年代 (Old) │ │ │ │ │ └─────────────────┘ │ │ │ └───────────────────────┘ │ │ │ │ ┌───────────────────────┐ │ │ │ 方法区 │ 线程共享 │ │ │ (Method Area) │ │ │ │ │ │ │ │ · 类信息 │ │ │ │ · 常量池 │ │ │ │ · 静态变量 │ │ │ │ · JIT编译后的代码 │ │ │ └───────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ ┌───────────────────────┐ │ 直接内存 │ (堆外内存) │ (Direct Memory) │ │ │ │ · NIO Buffer │ │ · Netty Zero-Copy │ └───────────────────────┘ 关键特征: ...