JVM 内存结构比较官方的说法是“运行时数据区”,它分为公有和私有两个部分——公有部分是 所有线程共享的,指 Java 堆、方法区、常量池;私有部分是和线程一一对应的,包括 PC 寄存器、虚拟机栈、本地方法栈。

公有部分

堆内存

Java 堆指的是从 JVM 划分出来的一块区域,这块区域专门用于 Java 实例对象的内存分配, 几乎所有实例对象都会在这里进行内存的分配。之所以说几乎是因为有特殊情况,有些时候 小对象会直接在栈上进行分配

根据对象存活时间的不同,Java 堆还被分为年轻代、老年代两个区域,年轻代还被进一步 划分为 Eden 区、From Survivor 0、To Survivor 1 区。如下图所示:

当有对象需要分配时,永远优先被分配在年轻代的 Eden 区,等到 Eden 区域内存不够时, Java 虚拟机会启动垃圾回收(GC)。此时 Eden 区中没有被引用的对象的内存就会被回收, 而一些存活时间较长的对象则会进入到老年代。在 JVM 中有一个名为 -XX:MaxTenuringThreshold 的参数专门用来设置晋升到老年代所所需要经历的 GC 次数

方法区(元空间)

方法区指的是存储 Java 类字节码数据的一块区域,它存储了每一个类的结构信息,例如运 行时常量池、字段和方法数据、构造方法等

方法区在不同版本的虚拟机有不同的表现形式,例如在 1.7 版本的 HotSpot 虚拟机中,方 法区被称为永久代(Permanent Space),而在 JDK 1.8 中则被称为元空间(MetaSpace)

私有部分

PC 寄存器

Program Counter 寄存器,用来保存线程当前正在执行的方法。如果这个方法不是 native 方法,那么 PC 寄存器就保存 Java 虚拟机正在执行的字节码指令地址。如果是 native 方 法,那么 PC 寄存器保存的值是 undefined 。任意时刻,一条 Java 虚拟机线程只会执行 一个方法的代码,而这个被线程执行的方法称为该线程的当前方法,其地址被存在 PC 寄存 器中

虚拟机栈

Java 虚拟机栈与线程同时创建,用来存储栈帧,即存储局部变量与一些过程结果的地方。 栈帧存储的数据包括:局部变量表、操作数栈。

本地方法栈

当 Java 虚拟机使用其他语言(例如 C 语言)来实现指令集解释器时,也会使用到本地方 法栈。如果 Java 虚拟机不支持 natvie 方法,并且自己也不依赖传统栈的话,可以无需支 持本地方法栈。