`

jvm体系结构

    博客分类:
  • jvm
 
阅读更多

VM可以由不同的厂商来实现。由于厂商的不同必然导致JVM在实现上的一些不同,然而JVM还是可以实现跨平台的特性,这就要归功于设计JVM时的体系结构。

我们知道,一个JVM实例的行为不光是它自己的事,还涉及到它的子系统、存储区域、数据类型和指令这些部分,它们描述了JVM的一个抽象的内部体系结构,其目的不光规定实现JVM时它内部的体系结构,更重要的是提供了一种方式,用于严格定义实现时的外部行为。每个JVM都有两种机制,一个是装载具有合适名称的类(类或是接口),叫做类装载子系统;另外的一个负责执行包含在已装载的类或接口中的指令,叫做运行引擎。每个JVM又包括方法区、堆、Java栈、程序计数器和本地方法栈这五个部分,这几个部分和类装载机制与运行引擎机制一起组成的体系结构图为:


类装载子系统

分为启动类装载器与用户自定义类装载器,前者是java虚拟机实现的一部分,后者是程序的一部分,分为拥有不同的名称空间。

类装载器负责装载,连接,初始化

装载:查找并装载二进制文件数据

连接:执行验证(类文件的正确性),准备(为类型分配内存,并初始化),解析(把符号引用转为直接引用)

初始化:初始化类变量

classloader关键方法

defineclass(String name,byte[] data,int offset,int len);

defineclass(string name,byte[] data,int offset,int len,protectiondomain doamin);

将data[offset]到data[offset+len]的二进制数据装载方法区中,也就是一个由name命名的类数据,domain为指定的安全域。

findsystemclass(String classname)

接受classname(类的全限定名)调用启动类装载器加载指定类,如果没有相关类会抛classnotfoundexception

resolveclass()接受class实例的引用,defineclass负责装载类到方法区,该方法负载连接

方法区

方法区存放类相关信息,类变量,方法等,注意是类,不是实例,线程共享方法区,因此必须考虑线程安全问题,方法区可以被垃圾回收

方法区存放的类型信息(类的类型信息)包括

类型的全限定名

类型的直接超类的全限定名

类型是类还是接口

类型的访问修饰符

类型直接超类的有序列表

全限定名:java/lang/Integer 也就是.替换为/

除了类型信息还保存

该类型的常量

字段信息

方法信息

类变量

classloader引用 

class引用 

常量池:保存对字段,方法的符号引用。

字段信息:字段名,类型,修饰符

方法信息:方法名,参数个数及类型,返回类型,修饰符,如果不是抽象的,还包括字节码,操作数栈,该方法在栈中局部变量的大小,异常。

运行时创建的实例与数组都放入堆,被所有线程共享,可以被内存回收

程序计数器(pc寄存器)

那么PC寄存器的值总是指示下一条将要被执行的命令(命令的地址)

java栈

而它的java栈总是存储该线程中java方法调用的状态--包括它的局部变量、被调用时传进来的参数、它的返回值、以及运算的中间结果等等

java栈是由许多栈帧(stack frame)或者说帧组成的。一个栈帧包含一个java方法的调用状态。当线程调用一个java方法时,虚拟机压入一个新的栈帧到该线程的java栈中;当该方法返回时,这个栈帧被从java栈中弹出并抛弃。

 

栈帧

由3部分组成:局部变量区、操作数栈、帧数据区。局部变量区和操作数栈的大小要视对应的方法而定,它们是按字长计算的。编译器在编译时就确定了这些值并保存在class文件中,而帧数据区的大小依赖于具体的实现。

局部变量区:用于存放方法的参数和局部变量,编译器首先按声明的顺序把这些参数放入局部变量数组。局部变量区被组织为一个以字长为单位、从0开始计数的数组,指令是以索引来访问局部变量的。

操作数栈:和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组、但是和前者不同的是,它不是通过索引来访问的,而是通过标准的栈操作--压栈和出栈来访问的。虚拟机没有寄存器,所以java虚拟机的指令是从操作数栈中而不是寄存器中取得操作数的。

帧数据区:除了局部变量区和操作数栈外,java栈帧还需要一些数据来支持常量池解析、正常方法返回以及异常派发机制,这些信息都保存在java栈帧的帧数据区中。

本地方法栈

当一个线程调用本地方法时,它就不再受到虚拟机关于结构和安全限制方面的约束,它既可以访问虚拟机的运行期数据区,也可以使用本地处理器以及任何类型的栈。例如,本地栈是一个C语言的栈,那么当C程序调用C函数时,函数的参数以某种顺序被压入栈,结果则返回给调用函数。在实现Java虚拟机时,本地方法接口使用的是C语言的模型栈,那么它的本地方法栈的调度与使用则完全与C语言的栈相同。

执行引擎

基于对操作数的出栈和入栈操作进行的,相对比较简单,没有寄存器。当然运行期优化时候把字节码编译为本地代码的时候,会充分利用机器的寄存器的。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics