JVM之运行时数据区(Runtime Data Area)
这里主要以JDK8之后的JVM内存布局为介绍重点,首先看一张图
从图中可以看出运行时数据区主要分为以下几部分:
1.程序计数器:
2.本地方法栈:
3.虚拟机栈
4.堆区
5.元空间(永久代)
这几部分中有线程共享的和单独线程私有的。即
1.独立线程私有:包括程序计数器、虚拟机栈、本地方法栈
2.线程间共享:堆区、堆外内存(永久代或者元空间、代码缓存)
程序计数器
一块很小的内存空间,几乎可以忽略
生命周期以线程的生命周期保持一致。
并非是物理寄存器,JVM是对物理PCR的一种模拟。
作用:用来存储指向下一条指令的地址,由执行引擎读取下一条指令
虚拟机栈(Java栈)
1.每个线程创建时都会创建一个虚拟机栈,内部保存一个个的栈帧,一个栈帧对应一个方法
2.生命周期与线程的生命周期保持一致。
3.作用:负责Java程序的运行,保存方法的局部变量,部分结果。参与方法的调用和返回。
JVM对虚拟机栈的操作只有两个:
1.每个方法的执行,伴随着入栈操作
2.方法执行结束后的出栈操作
栈帧的内部结构
每个栈帧中存储以下:
1.局部变量表(Local Variables)
2.操作数栈(Operand Stack)(或表达式栈)
3.动态链接(Dynamic Linking)
4.方法返回地址(Return Address)
5.一些附加信息
局部变量表(局部变量数组或本地变量表)
1.定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量
2.局部变量表中的变量只在当前方法中调用有效,当方法调用结束后,随着栈帧的销毁,局部变量表也随之销毁。
在方法体内的局部变量
2.局部变量表中的变量只在当前方法中调用有效,当方法调用结束后,随着栈帧的销毁,局部变量表也随之销毁。
操作数栈(Operand Stack)
1.主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间
2.在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈和出栈
3.如果被调用的方法带有返回值的话,其返回值会被压入当前栈的操作数栈中。并且会更新PC寄存器中下一条需要执行的字节码指令
下面举个简单的例子吧。
首先是代码举例
首先看下这个栈帧中的局部变量表吧
其对应的字节码指令信息如下:
下面是字节码指令信息解释:
1.bipush: Push byte
2.istore: Store int into local variable
3.iload: Load int from local variable
4.iadd: Add int
5.getstatic: Get static field from class
6.invokevirtual: Invoke instance method; dispatch based on class 编译期间不能确定的方法
7.return: Return void from method
扩充点其他的知识
方法的调用:虚方法和非虚方法
非虚方法:如果方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的。这样的方法就称为非虚方法。
非虚方法包括:静态方法、私有方法、final方法,实例构造器、父类方法
其他方法称为虚方法。
虚拟机中提供了几条方法调用指令
1.普通调用指令:
invokestatic:调用静态方法,解析阶段确定唯一方法的版本。
invokespecial:调用私有和父类方法,解析阶段确定唯一方法版本
invokevirtual: 调用所有虚方法
invokeinterface:调用接口方法
2.动态调用指令
invokedynamic:动态解析出需要调用的方法,然后执行。
动态链接(指向运行时常量池的方法引用)
在Java源文件编译成字节码文件时,所有的变量和方法引用会作为符号引用保存在class文件的常量池里。动态链接的作用将这些符号引用转换为调用方法的直接引用,
这里可以理解为引用方法区里运行时常量池的各种引用。
方法返回地址
存放调用该方法的PC寄存器的值。
方法正常退出时,调用者的PC寄存器的值作为返回地址返回给执行引擎,执行引擎然后开始执行下一条指令。即调用该方法的指令的下一条指令的地址
异常退出的,返回地址通过异常表现来确定,栈帧中不会保存这部分信息。
一些附加信息
可选部分,会携带比如对程序调试提供支持的附加信息。
本地方法栈(Native Method Stack)
Java虚拟机栈用来管理Java方法的调用,而本地方法栈用于管理本地方法的调用
Java虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的 Native 方法服务。
虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。
Navtive 方法是 Java 通过本地方法接口(JNI) 直接调用本地 C/C++ 库,可以认为是 Native 方法相当于 C/C++ 暴露给 Java 的一个接口,Java 通过调用这个接口从而调用到 C/C++ 方法。
本地方法接口的简单理解
本地方法:简单理解一个本地方法就是一个Java方法调用非Java代码的接口。该方法的实现由非Java语言实现。
定义一个本地方法时,不提供实现体。下面是一些本地方法举例。
本地接口的作用是融合其他的编程语言为Java语言使用。主要为C/C++语言。
使用Native Method的原因?
1.与Java环境外交互:Java应用需要与Java外面的环境交互,这是本地方法的主要原因。
2.与操作系统交互:通过使用本地方法,得以用Java实现jre的与底层系统的交互,