jvm所管理的内存包括以下几个运行时数据区域
图中灰色的为线程共享,无色的为线程独享。
或如下图所示:
程序计数器(Program Counter Register)是线程私有的内存空间(每个线程都有一个属于自己的pcr)。一个线程的程序计数器用于控制该线程的执行。
程序计数器可以看做是当前线程所执行字节码的行号指示器,字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、线程恢复等功能都需要依赖程序计数器。
如果线程正在执行的是一个java方法,计数器记录的是正在执行的字节码指令的地址;如果正在执行的是Native方法,计数器的值为空。
虚拟机栈(JVM Stack)也是线程私有的,生命周期与线程相同。虚拟机栈描述的是方法的执行模型。
每个方法在执行时都会创建一个帧压入栈中,用于存储局部变量表、操作数栈、方法出口信息等。
局部变量表存放了编译期可知的各种基本数据类型(byte、char、int)、对象引用类型和returnAddress类型。
局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,后者服务于java方法,前者Native方法。
堆(Heap) 堆与方法区是所有线程共享的内存区域。此内存区域的唯一目的就是存放对象实例(包括数组,数组也是引用类型)。
创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。
方法区(Method Area) 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
类存储在JVM的方法区中,而对象存储在堆中。类似于汇编中的代码段和数据段。
运行时常量池是方法区的一部分。
Class文件中除了类的版本、字段、方法、接口等描述信息,还有常量池,用于存放编译期生成的各种字面量和符号引用。
相较于Class文件常量池,运行时常量池更具动态性,在运行期间也可以将新的变量放入常量池中,而不是一定要在编译时确定的常量才能放入。
参考:
《深入理解Java虚拟机》
https://www.programcreek.com/2013/04/jvm-run-time-data-areas/