您的位置:首页 > 编程语言 > Java开发

java虚拟机02-体系结构

2015-11-11 19:15 330 查看
除了指令集,JVM主要由四部分构成:类加载器,执行引擎,内存区域,本地方法调用。

类加载器:在JVM启动或者类运行时,将需要的class加载到内存中。

执行引擎:负责执行java字节码中包含的字节码指令,相当于实际机器上的CPU。

内存区:将内存划分为多个区,来模拟实际机器上的存储,记录和调度功能模块。

本地方法调用:调用c或c++实现的本地方法代码并返回结果。



执行引擎详解:解析java字节码指令,得到执行的结果。在《java虚拟机规范》中定义了执行引擎遇到每条字节码指令时应该处理什么,并且得到什么结果。但是并没有规定执行引擎应该采取什么方式处理而得到这个结果。因为执行引擎具体采取什么方式处理由JVM的实现厂商自己去实现,是直接解释解析还是采用JIT技术转成本地代码去执行,还是采用寄存器这个芯片模式去执行都可以。所以执行引擎的具体实现有很大发挥空间,例如SUN的Hotspot是基于栈的执行引擎,谷歌的Dalvik是基于寄存器的执行引擎。执行引擎也就是执行一条条代码的一个流程。而代码都是包含在方法体内的,所以执行引擎本质就是执行一个个方法所串起来的流程,对应到操作系统中一个执行流程是一个java进程还是一个java线程呢?因为一个java进程可以有多个同时执行的执行流程。这样说来,每个java线程就是执行引擎的一个实例,那么一个JVM实例中就会同时有多个执行引擎在工作,这些执行引擎有的在执行用户的程序,有的在执行JVM内部的程序。

Java内存管理

执行引擎在执行一段程序时需要存储一些东西,如操作码需要的操作数,操作码的结果需要保存。class类的字节码还有类的对象这些信息都需要在执行引擎执行之前就准备好。一个JVM实例会有一个方法区,栈,程序计数器,堆,本地方法区。其中方法区和堆是所有线程共有的,也就是可以被所有的执行引擎实例所访问。每一个新的执行引擎实例 被创建时都会创建一个栈和PC寄存器,如果当前正在执行一个java方法,那么当前的这个java栈中保存的是该线程中方法调用的状态,包括方法的参数,方法的局部变量,方法的返回值以及运算的中间结果等。而PC寄存器会执行即将执行的下一条指令。

JVM为何选择基于栈的架构

JVM执行字节码指令是基于栈的架构,也就是所有的操作数必须先入栈,然后根据指令中的操作码选择从栈顶弹出若干个元素进行计算后再将结果压入栈中。JVM中操作数可以存放在每一个栈帧中的一个本地变量集中,即每个方法调用时都会给这个方法分配一个本地变量集,这个本地变量集在编译时就已经确定,所以操作数入栈可以直接是常量入栈或者从本地变量集中取一个变量压入栈中。例如进行一个加法计算,如果两个操作数都在本地变量中,那么一个加法操作需要有5次栈操作,首先两个操作数从本地变量依次入栈(两次),再讲两个操作数出栈进行加法运算(2次出栈),最后将加法结果压入栈顶(1次入栈)。

JVM为何要基于栈来设计?

有三个理由:一个是JVM要设计成平台无关的,而平台无关性就要保证在没有或者有很少的寄存器的机器上也要同样能正确执行java代码。第二个理由是为JVM更好地优化代码而设计的,编译器一般采用以栈为基础的结构向连接器或者优化器传递这种编译的中间结果。而对于java来说,JVM可作为连接器使用,也可以作为优化器使用。这种以栈为中心的体系结构可以将运行时进行的优化工作与执行即时编译或者自适应优化的执行引擎集合起来,从而可以更好地优化执行java字节码指令。第三个利用是为了指令的紧凑性,因为java的字节码可能在网络上传输,所以class文件的大小也是设计JVM字节码指令的一个重要因素,如class文件中字节码除了处理两个表跳转的指令外,其他都是字节对其的,操作码可以只占一个字节大小,这都是为了尽量让编译后的class文件更加紧凑。为了提高字节码在网络中的传输效率,Sun设计了一个Jar包的压缩工具Pack200,它可以将多个class文件中的重复的常量池的信息进行合并,如,一般每个class文件中都会含有“Ljava/lang/String;”,那么多个class中的常量就可以共用,从而减少数据量的使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: