Java虚拟机 运行时数据区
1.PC寄存器(Program Counter)
JVM可以同时运行多个线程,每个线程对应有自己的PC寄存器。
如果JVM当前运行的方法是非Native方法,那么PC寄存器中保存的是JVM正在执行的字节码指令的地址。
如果当前运行的方法是Native方法,PC寄存器中保存的值是undefined。
2.Java虚拟机栈(Java Virtual Machine Stack)
每条线程对应有自己的虚拟机栈,虚拟机栈中存储着栈帧(Frame)。
3.Java堆
各条线程共享的运行时内存区域,堆(Heap)供所有类实例和数组对象分配内存。
Java堆是垃圾收集器(Garbage Collector)的主要操作对象。
4.方法区(Method Area)
各条线程共享的运行时内存区域。
存储了每一个类的结构信息,例如运行时常量池,字段,方法数据,构造函数和普通方法的字节码内容等等。
方法区在虚拟机启动的是被创建。
5.运行时常量池(Runtime Constant Pool)
每个类和或接口的常量池的运行时表示形式,它包括了若干种不同的常量:从编译期可知的数值字面量到必须运行期解析后才能获得的方法或字段引用。
6.本地方法栈(Native Method Stack)
Java虚拟机实现可能会使用到传统的栈(通常称之为“C Stacks”)来支持native方法(指使用Java以外的其他语言编写的方法)的执行,
这个栈就是本地方法栈。当Java虚拟机使用其他语言(例如C语言)来实现指令集解释器时,也会使用到本地方法栈。
7.栈帧(Frame)
栈帧用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接,方法返回值和异常分配。
栈帧随着方法调用而分配,方法结束而销毁。无论方法是正常结束,还是抛出异常都作为方法结束。
栈帧存储在Java虚拟机栈中,每个栈帧都有自己的局部变量表,操作数栈和指向当前方法所属的类的运行时常量池的引用。
在一条线程之中,只有目前正在执行的那个方法的栈帧是活动的。这个栈帧就被称为是当前栈帧(Current Frame),
这个栈帧对应的方法就被称为是当前方法(Current Method),定义这个方法的类就称作当前类(Current Class)。
对局部变量表和操作数栈的各种操作,通常都指的是对当前栈帧的对局部变量表和操作数栈进行的操作。
7.1 局部变量表(Local Variables)
每个栈帧内部都包含一组称为局部变量表的变量列表。
一个局部变量可以保存一个类型为Boolean、Byte、Short、float、reference和returnAddress的数据,两个局部变量可以保存类型为Double和long的数据。
局部变量表使用索引来定位和访问,第一个局部变量的索引值为0。
7.2 操作数栈(Operand Stack)
每个栈帧内部都包含一个称为操作数栈的先进后出(FIFO)栈。
操作数栈所属的栈帧在刚刚被创建的时候,操作数栈是空的。Java虚拟机提供一些字节码指令来从局部变量表或者对象实例的字段中复制常量或变量值到操作数栈中,
也提供了一些指令用于从操作数栈取走数据、操作数据和把操作结果重新入栈。在方法调用的时候,操作数栈也用来准备调用方法的参数以及接收方法返回结果。
每一个操作数栈的成员(Entry)可以保存一个Java虚拟机中定义的任意数据类型的值,包括long和double类型。
在操作数栈中的数据必须被正确地操作,这里正确操作是指对操作数栈的操作必须与操作数栈栈顶的数据类型相匹配,例如不可以入栈两个int类型的数据,
然后当作long类型去操作他们,或者入栈两个float类型的数据,然后使用iadd指令去对它们进行求和。
7.3 动态链接(Dynamic Linking)
每一个栈帧内部都包含一个指向运行时常量池的引用来支持当前方法的代码实现动态链接。
在Class文件里面,描述一个方法调用了其他方法,或者访问其成员变量是通过符号引用(Symbolic Reference)来表示的,
动态链接的作用就是将这些符号引用所表示的方法转换为实际方法的直接引用。
类加载的过程中将要解析掉尚未被解析的符号引用,并且将变量访问转化为访问这些变量的存储结构所在的运行时内存位置的正确偏移量。
7.4 方法正常调用完成
方法正常调用完成是指在方法的执行过程中,没有任何异常被抛出——包括直接从Java虚拟机之中抛出的异常以及在执行时通过throw语句显式抛出的异常。
如果当前方法调用正常完成的话,它很可能会返回一个值给调用它的方法,方法正常完成发生在一个方法执行过程中遇到了方法返回的字节码指令的时候,
使用哪种返回指令取决于方法返回值的数据类型(如果有返回值的话)。
在这种场景下,当前栈帧承担着回复调用者状态的责任,其状态包括调用者的局部变量表、操作数栈和被正确增加过来表示执行了该方法调用指令的程序计数器等。
使得调用者的代码能在被调用的方法返回并且返回值被推入调用者栈帧的操作数栈后继续正常地执行。
7.5 方法异常调用完成
方法异常调用完成是指在方法的执行过程中,某些指令导致了Java虚拟机抛出异常,并且虚拟机抛出的异常在该方法中没有办法处理,
或者在执行过程中遇到了athrow字节码指令显式地抛出异常,并且在该方法内部没有把异常捕获住。如果方法异常调用完成,
那一定不会有方法返回值返回给它的调用者。
1.PC寄存器(Program Counter)
JVM可以同时运行多个线程,每个线程对应有自己的PC寄存器。
如果JVM当前运行的方法是非Native方法,那么PC寄存器中保存的是JVM正在执行的字节码指令的地址。
如果当前运行的方法是Native方法,PC寄存器中保存的值是undefined。
2.Java虚拟机栈(Java Virtual Machine Stack)
每条线程对应有自己的虚拟机栈,虚拟机栈中存储着栈帧(Frame)。
3.Java堆
各条线程共享的运行时内存区域,堆(Heap)供所有类实例和数组对象分配内存。
Java堆是垃圾收集器(Garbage Collector)的主要操作对象。
4.方法区(Method Area)
各条线程共享的运行时内存区域。
存储了每一个类的结构信息,例如运行时常量池,字段,方法数据,构造函数和普通方法的字节码内容等等。
方法区在虚拟机启动的是被创建。
5.运行时常量池(Runtime Constant Pool)
每个类和或接口的常量池的运行时表示形式,它包括了若干种不同的常量:从编译期可知的数值字面量到必须运行期解析后才能获得的方法或字段引用。
6.本地方法栈(Native Method Stack)
Java虚拟机实现可能会使用到传统的栈(通常称之为“C Stacks”)来支持native方法(指使用Java以外的其他语言编写的方法)的执行,
这个栈就是本地方法栈。当Java虚拟机使用其他语言(例如C语言)来实现指令集解释器时,也会使用到本地方法栈。
7.栈帧(Frame)
栈帧用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接,方法返回值和异常分配。
栈帧随着方法调用而分配,方法结束而销毁。无论方法是正常结束,还是抛出异常都作为方法结束。
栈帧存储在Java虚拟机栈中,每个栈帧都有自己的局部变量表,操作数栈和指向当前方法所属的类的运行时常量池的引用。
在一条线程之中,只有目前正在执行的那个方法的栈帧是活动的。这个栈帧就被称为是当前栈帧(Current Frame),
这个栈帧对应的方法就被称为是当前方法(Current Method),定义这个方法的类就称作当前类(Current Class)。
对局部变量表和操作数栈的各种操作,通常都指的是对当前栈帧的对局部变量表和操作数栈进行的操作。
7.1 局部变量表(Local Variables)
每个栈帧内部都包含一组称为局部变量表的变量列表。
一个局部变量可以保存一个类型为Boolean、Byte、Short、float、reference和returnAddress的数据,两个局部变量可以保存类型为Double和long的数据。
局部变量表使用索引来定位和访问,第一个局部变量的索引值为0。
7.2 操作数栈(Operand Stack)
每个栈帧内部都包含一个称为操作数栈的先进后出(FIFO)栈。
操作数栈所属的栈帧在刚刚被创建的时候,操作数栈是空的。Java虚拟机提供一些字节码指令来从局部变量表或者对象实例的字段中复制常量或变量值到操作数栈中,
也提供了一些指令用于从操作数栈取走数据、操作数据和把操作结果重新入栈。在方法调用的时候,操作数栈也用来准备调用方法的参数以及接收方法返回结果。
每一个操作数栈的成员(Entry)可以保存一个Java虚拟机中定义的任意数据类型的值,包括long和double类型。
在操作数栈中的数据必须被正确地操作,这里正确操作是指对操作数栈的操作必须与操作数栈栈顶的数据类型相匹配,例如不可以入栈两个int类型的数据,
然后当作long类型去操作他们,或者入栈两个float类型的数据,然后使用iadd指令去对它们进行求和。
7.3 动态链接(Dynamic Linking)
每一个栈帧内部都包含一个指向运行时常量池的引用来支持当前方法的代码实现动态链接。
在Class文件里面,描述一个方法调用了其他方法,或者访问其成员变量是通过符号引用(Symbolic Reference)来表示的,
动态链接的作用就是将这些符号引用所表示的方法转换为实际方法的直接引用。
类加载的过程中将要解析掉尚未被解析的符号引用,并且将变量访问转化为访问这些变量的存储结构所在的运行时内存位置的正确偏移量。
7.4 方法正常调用完成
方法正常调用完成是指在方法的执行过程中,没有任何异常被抛出——包括直接从Java虚拟机之中抛出的异常以及在执行时通过throw语句显式抛出的异常。
如果当前方法调用正常完成的话,它很可能会返回一个值给调用它的方法,方法正常完成发生在一个方法执行过程中遇到了方法返回的字节码指令的时候,
使用哪种返回指令取决于方法返回值的数据类型(如果有返回值的话)。
在这种场景下,当前栈帧承担着回复调用者状态的责任,其状态包括调用者的局部变量表、操作数栈和被正确增加过来表示执行了该方法调用指令的程序计数器等。
使得调用者的代码能在被调用的方法返回并且返回值被推入调用者栈帧的操作数栈后继续正常地执行。
7.5 方法异常调用完成
方法异常调用完成是指在方法的执行过程中,某些指令导致了Java虚拟机抛出异常,并且虚拟机抛出的异常在该方法中没有办法处理,
或者在执行过程中遇到了athrow字节码指令显式地抛出异常,并且在该方法内部没有把异常捕获住。如果方法异常调用完成,
那一定不会有方法返回值返回给它的调用者。