1、程序计数器
程序计数器(Program Counter Register),也叫PC寄存器,是一块较小的内存空间,它可以看作是当前线程所执行的字节码指令的行号指示器。字节码解释器的工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
2、Java 虚拟机栈
虚拟机栈也是线程私有,而且生命周期与线程相同,每个Java方法在执行的时候都会创建一个栈帧(Stack Frame)。
2.1 栈帧
栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。
每一个方法从调用至执行完成的过程,都对应着一个栈帧在虚拟机栈里从入栈到出栈的过程。
2.2 局部变量表
局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内定义的局部变量。
一个局部变量可以保存一个类型为 boolean、byte、char、short、int 、float、reference和returnAddress类型 的数据。reference类型表示对一个对象实例的引用。returnAddress类型是为jsr、jsr_w和ret指令服务的,目前已经很少使用了。
局部变量表的容量以变量槽(Variable Slot)为最小单位,Java虚拟机规范并没有定义一个槽所应该占用内存空间的大小,但是规定了一个槽应该可以存放一个32位以内的数据类型。
2.3 操作数栈
操作数栈(Operand Stack)也常称为操作栈,它是一个 后入先出栈(LIFO) 。
当一个方法刚刚开始执行时,其操作数栈是空的,随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。一个完整的方法执行期间往往包含多个这样出栈/入栈的过程。
操作数栈的每一个元素可以是任意Java数据类型,32位的数据类型占一个栈容量,64位的数据类型占2个栈容量。
2.4 动态连接
在一个class文件中,一个方法要调用其他方法,需要将这些方法的符号引用转化为其在内存地址中的直接引用,而符号引用存在于方法区中的运行时常量池。
Java虚拟机栈中,每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用,持有这个引用的目的是为了支持方法调用过程中的动态连接(Dynamic Linking)。
这些符号引用一部分会在类加载阶段或者第一次使用时就直接转化为直接引用,这类转化称为静态解析。另一部分将在每次运行期间转化为直接引用,这类转化称为动态连接。
2.5 方法返回
当一个方法开始执行时,可能有两种方式退出该方法:
正常完成出口
异常完成出口
正常完成出口是指方法正常完成并退出,没有抛出任何异常。如果当前方法正常完成,则根据当前方法返回的字节码指令,这时有可能会有返回值传递给方法调用者(调用它的方法),或者无返回值。具体是否有返回值以及返回值的数据类型将根据该方法返回的字节码指令确定。
异常完成出口 是指方法执行过程中遇到异常,并且这个异常在方法体内部没有得到处理,导致方法退出。
2.6 附加信息
虚拟机规范允许具体的虚拟机实现增加一些规范中没有描述的信息到栈帧之中,例如和调试相关的信息,这部分信息完全取决于不同的虚拟机实现。在实际开发中,一般会把动态连接,方法返回地址与其他附加信息一起归为一类,称为栈帧信息。
3、本地方法栈
本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。
简单地讲,一个Native Method就是一个java调用非java代码的接口。
4、Java 堆
对于Java应用程序来说,Java堆(Java Heap)是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java世界里“几乎”所有的对象实例都在这里分配内存。
4.1堆内存划分
新生代
Eden空间[伊甸园]
From Survivor空间
To Survivor空间
老年代
堆大小 = 新生代 + 老年代。
堆的大小可通过参数
-Xms(堆的初始容量)
-Xmx(堆的最大容量) 来指定。
5、方法区
方法区是线程共享,存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等等。
jdk1.7之前,HotSpot虚拟机对于方法区的实现称之为“永久代”, Permanent Generation 。
jdk1.8之后,HotSpot虚拟机对于方法区的实现称之为“元空间”, Meta Space 。
方法区是Java虚拟机规范中的定义,是一种规范,而永久代和元空间是 HotSpot 虚拟机不同版本的两种实现。
5.1. 元空间和永久代有什么不同
存储位置不同,永久代物理是堆的一部分,和新生代,老年代地址是连续的,而元空间属于本地内存;
存储内容不同,元空间存储类的元信息,[静态变量]和[常量池]等并入堆中。 相当于永久代的数据被分到了堆和元空间中。
6、运行时常量池和字符串常量池
Class文件中除了有类的版本、字段、方法、接口等描述信息外
还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
字面量:
双引号引起来的字符串值,“kkb”
定义为final类型的基本类型。
double,long,float
符号引用:
类或接口的全限定名(包括他的父类和所实现的接口)
变量或方法的名称
变量或方法的描述信息
方法的描述:参数个数、参数类型、方法返回类型等等
变量的描述信息:变量的返回值
this