运行时数据区
Java虚拟机在执行程序的过程中,会将内存划分为若干个不同的数据区域,这些若干个不同的数据区域组合在一起称为运行时数据区
。运行时数据区可划分为两类。一类是线程独有的(程序计数器、Java虚拟机栈、和本地方法栈),随线程的启动和结束而建立和销毁;另一类是所有线程共享的(Java堆和方法区),随着虚拟机进程的启动而一直存在。
程序计数器
每个线程都有一个独立的程序计数器
,各个线程之间的计数器互不影响。程序计数器记录了字节码指令的地址,他用来告诉线程应执行哪条指令。
Java虚拟机栈
Java虚拟机栈
为执行Java方法提供服务。每一个方法被调用到执行结束的过程,对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
栈帧
每一个栈帧
都包含局部变量表、操作数栈、动态连接、方法返回地址等信息。栈帧中需要多大的局部变量表,需要多深的操作数栈在编译期就已经被计算出来,并且写入到方法表的Code属性之中。也就是说,一个栈帧需要分配多大的内存在编译期已经决定,不受运行期的影响。
局部变量表
的大小在编译期就已经确定,该大小存储在方法表的Code属性之中。局部变量表存放了编译期可知的各种Java虚拟机基本数据类型、对象引用。操作数栈
的深度在编译期就已经确定,该深度也存储在方法表的Code属性之中。我们可以将操作数栈理解为数据计算的区域。动态连接
每一个栈帧都有一个指向运行时常量池中该方法的引用。这个引用用来支持方法调用过程中的动态连接。方法返回地址
由PC计数器或异常表来确定。如果是正常退出,方法的返回地址就是主调方法调用点地址;如果是异常退出,方法的返回地址通过异常表来确定。
前面提到方法退出的两种方式。正常退出
是指执行引擎遇到方法返回的字节码指令,这个时候会将返回值传递给上层的方法调用者。异常退出
是指方法在执行的过程中,某些指令导致Java虚拟机抛出异常并且该异常在本方法的异常表没有办法处理,或者Athrow字节码指令显示抛出异常并且在本方法中没有进行异常捕获,这个时候就会导致方法退出。如果是异常退出,是一定不会有返回值给上层方法调用者的。无论哪种退出,都需要恢复上层方法的局部变量表和操作数栈;如果有返回值,需要将返回值压入调用者栈帧的操作数栈中;还需要调整PC计数器指向方法调用的后面一条指令。
本地方法栈
本地方法栈
与Java虚拟机栈的作用类似,为执行本地方法提供服务。
Java堆
Java堆
是被所有线程共享的一块内存区域,几乎所有的对象实例都分配在这块内存区域。
方法区
方法区
也是被所有线程共享的一块内存区域,它用于存储已被虚拟机加载的类型信息、字段信息、方法信息、常量、静态变量等数据。