java运行机制详解|jvm规格描述

洛阳泰山 洛阳泰山     2023-03-02     474

关键词:

()  Java应用程序的开发

   Java应用程序的开发周期包括编译、下载、解释和执行几个部分。Java编译程序将 Java源程序翻译为JVM可执行代码--字节码。这一编译过程同C/C++的编译有些不同。当C编译器编译生成一个对象的代码时,该代码是为在某一特定硬件平台运行而产生的。因此,在编译过程中,编译程序通过查表将所有对符号的引用转换为特定的内存偏移量,以保证程序运行。Java编译器却不将对变量和方法的引用编译为数值引用,也不确定程序执行过程中的内存布局,而是将这些符号引用信息保留在字节码中,由解释器在运行过程中创立内存布局,然后再通过查表来确定一个方法所在的地址。这样就有效的保证了Java的可移植性和安全性。

运行JVM字节码的工作是由解释器( java命令 )来完成的。

解释执行过程分三部进行:代码的装入、代码的校验和代码的执行。

装入代码的工作由"类装载器"class loader)完成。类装载器负责装入运行一个程序需要的所有代码,这也包括程序代码中的类所继承的类和被其调用的类。当类装载器装入一个类时,该类被放在自己的名字空间中。除了通过符号引用自己名字空间以外的类,类之间没有其他办法可以影响其他类。在本台计算机上的所有类都在同一地址空间内,而所有从外部引进的类,都有一个自己独立的名字空间。这使得本地类通过共享相同的名字空间获得较高的运行效率,同时又保证它们与从外部引进的类不会相互影响。当装入了运行程序需要的所有类后,解释器便可确定整个可执行程序的内存布局。解释器为符号引用同特定的地址空间建立对应关系及查询表。通过在这一阶段确定代码的内存布局,Java很好地解决了由超类改变而使子类崩溃的问题,同时也防止了代码对地址的非法访问。

随后,被装入的代码由字节码校验器进行检查。校验器可发现操作数栈溢出,非法数据类型转化等多种错误。通过校验后,代码便开始执行了。

Java字节码的执行有两种方式:

1.即时编译方式:解释器先将字节码编译成机器码,然后再执行该机器码。

2.解释执行方式:解释器通过每次解释并执行一小段代码来完成Java字节码程序的所有操作。

通常采用的是第二种方法。由于JVM规格描述具有足够的灵活性,这使得将字节码翻译为机器代码的工作具有较高的效率。对于那些对运行速度要求较高的应用程序,解释器可将Java字节码即时编译为机器码,从而很好地保证了Java代码的可移植性和高性能。

(二)JVM规格描述


JVM的设计目标是提供一个基于抽象规格描述的计算机模型,为解释程序开发人员提很好的灵活性,同时也确保Java代码可在符合该规范的任何系统上运行。JVM对其实现的某些方面给出了具体的定义,特别是对Java可执行代码,即字节码(Bytecode)的格式给出了明确的规格。这一规格包括操作码和操作数的语法和数值、标识符的数值表示方式、以及Java类文件中的Java对象、常量缓冲池在JVM的存储映象。这些定义为JVM解释器开发人员提供了所需的信息和开发环境。Java的设计者希望给开发人员以随心所欲使用Java的自由。
JVM定义了控制Java代码解释执行和具体实现的五种规格,它们是:
JVM指令系统
JVM寄存器
JVM栈结构
JVM碎片回收堆
JVM存储区


2.1JVM指令系统


JVM指令系统同其他计算机的指令系统极其相似。Java指令也是由操作码和操作数两部分组成。操作码为8位二进制数,操作数进紧随在操作码的后面,其长度根据需要而不同。操作码用于指定一条指令操作的性质(在这里我们采用汇编符号的形式进行说明),如iload表示从存储器中装入一个整数,anewarray表示为一个新数组分配空间,iand表示两个整数的" "ret用于流程控制,表示从对某一方法的调用中返回。当长度大于8位时,操作数被分为两个以上字节存放。JVM采用了"big endian"的编码方式来处理这种情况,即高位bits存放在低字节中。这同 Motorola及其他的RISC CPU采用的编码方式是一致的,而与Intel采用的"little endian "的编码方式即低位bits存放在低位字节的方法不同。
Java指令系统是以Java语言的实现为目的设计的,其中包含了用于调用方法和监视多先程系统的指令。Java8位操作码的长度使得JVM最多有256种指令,目前已使用了160多种操作码。


2.2JVM指令系统


所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。如果虚拟机定义较多的寄存器,便可以从中得到更多的信息而不必对栈或内存进行访问,这有利于提高运行速度。然而,如果虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,这反而会降低虚拟机的效率。针对这种情况,JVM只设置了4个最为常用的寄存器。它们是:
pc程序计数器
optop操作数栈顶指针
frame当前执行环境指针
vars指向当前执行环境中第一个局部变量的指针
所有寄存器均为32位。pc用于记录程序的执行。optop,framevars用于记录指向Java栈区的指针。


2.3 JVM栈结构


作为基于栈结构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后,便为该代码中一个类的每一个方法创建一个栈框架,以保存该方法的状态信息。每个栈框架包括以下三类信息:
局部变量
执行环境
操作数栈
局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量。
执行环境用于保存解释器对Java字节码进行解释过程中所需的信息。它们是:上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。执行环境是一个执行一个方法的控制中心。例如:如果解释器要执行iadd(整数加法),首先要从frame寄存器中找到当前执行环境,而后便从执行环境中找到操作数栈,从栈顶弹出两个整数进行加法运算,最后将结果压入栈顶。
操作数栈用于存储运算所需操作数及运算的结果。


2.4 JVM碎片回收堆


Java类的实例所需的存储空间是在堆上分配的。解释器具体承担为类实例分配空间的工作。解释器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的使用。一旦对象使用完毕,便将其回收到堆中。
Java语言中,除了new语句外没有其他方法为一对象申请和释放内存。对内存进行释放和回收的工作是由Java运行系统承担的。这允许Java运行系统的设计者自己决定碎片回收的方法。在SUN公司开发的Java解释器和Hot Java环境中,碎片回收用后台线程的方式来执行。这不但为运行系统提供了良好的性能,而且使程序设计人员摆脱了自己控制内存使用的风险。


2.5 JVM存储区


JVM有两类存储区:常量缓冲池和方法区。常量缓冲池用于存储类名称、方法和字段名称以及串常量。方法区则用于存储Java方法的字节码。对于这两种存储区域具体实现方式在JVM规格中没有明确规定。这使得Java应用程序的存储布局必须在运行过程中确定,依赖于具体平台的实现方式。
JVM是为Java字节码定义的一种独立于具体平台的规格描述,是Java平台独立性的基础。目前的JVM还存在一些限制和不足,有待于进一步的完善,但无论如何,JVM的思想是成功的。
对比分析:如果把Java原程序想象成我们的C++原程序,Java原程序编译后生成的字节码就相当于C++原程序编译后的80x86的机器码(二进制程序文件),JVM虚拟机相当于80x86计算机系统,Java解释器相当于80x86CPU。在80x86CPU上运行的是机器码,在Java解释器上运行的是Java字节码。Java解释器相当于运行Java字节码的CPU,但该CPU不是通过硬件实现的,而是用软件实现的。Java解释器实际上就是特定的平台下的一个应用程序。只要实现了特定平台下的解释器程序,Java字节码就能通过解释器程序在该平台下运行,这是Java跨平台的根本。当前,并不是在所有的平台下都有相应Java解释器程序,这也是Java并不能在所有的平台下都能运行的原因,它只能在已实现了Java解释器程序的平台下运行。

Java宣称的一处编写随处运行就是由JVM来完成. sun的网站上你可以下载到基于各种cpu和各种操作系统的Jdkjre的下载版本,只要寻找到合适你使用的版本,以前你所编写的class文件copy到其他的机器上可以直接运行,不需要再编译。

其实j2se是一种规范,这种规范约定了其跨平台执行的所需要关注很多实现,基于该规范开发人员可以任意编写自己的Java代码而不需要关心这个程序可能在其他的机器和cpu上无法很好运行问题。

其实你也可以看到IbmWeblogic都有基于j2se规范的自己实现的Java 虚拟机 . 而且Sun所宣称的不需要编译而可以直接用class文件在各个JVM上直接运行并不精确,博格曾经遇到过用sun jre开发的class文件在ibm jre上有一个自动转换的过程,然后这个类可以很好的工作了,幸好这种情况是自动完成,否则我们又要陷入类似于各种c c++的版本编译器兼容性问题中。

以下下摘录了几个主要的概念:

JVM Java Virtual MachineJava虚拟机),它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 Java虚拟机有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。

JRE Java Runtime EnvironmentJava运行环境),运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。

JSDK Java Software Development Kit,和JDK以及J2SE等同。

JDK Java Development Kit(Java开发工具包):包括运行环境、编译工具及其它工具、源代码等,基本上和J2SE等同。

J2ME Java 2 Micro EditionJAVA2精简版)API规格基于J2SE ,但是被修改为可以适合某种产品的单一要求。J2ME使JAVA 程序可以很方便的应用于电话卡、寻呼机等小型设备,它包括两种类型的组件,即配置(configuration)和描述(profile)。

J2EE Java 2 Enterprise EditionJAVA2企业版),使用Java进行企业开发的一套扩展标准,必须基于J2SE,提供一个基于组件设计、开发、集合、展开企业应用的途径。J2EE 平台提供了多层、分布式的应用模型,重新利用组件的能力,统一安全的模式以及灵活的处理控制能力。 J2EE包括EJB, JTA, JDBC, JCA, JMX, JNDI, JMS, JavaMail, Servlet, JSP等规范。

J2SE Java 2 Standard EditionJAVA2标准版),用来开发Java程序的基础,包括编译器、小工具、运行环境,SUN发布的标准版本中还包括核心类库的所有源代码。

 

jvm系列-jvm类加载机制详解(代码片段)

...所有的.class字节码文件中的二进制数据读入内存中,导入运行时数据区的方法区中。当一个类首次被主动加载或被 查看详情

jvm类加载机制详解(代码片段)

...以从ZIP包中读取(比如从jar包和war包中读取),也可以在运行时计算生成(动态代理),也可以 查看详情

instrumentation接口详解(代码片段)

...立于应用程序之外的代理程序,可以用来监控和扩展JVM上运行的应用程序,相当于是JVM层面的AOP功能:监控和扩展JVM上的运行程序,替换和修改java类定义,提供一套代理机制,支持独立于JVM应用程序之外的程序以代理的方式连... 查看详情

jvm类加载机制详解类加载器与双亲委派模型

...2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。这里只是转化了数据结构,并未合并数据。(方法区就是用来存放已被加载的类信息,常量,静态变量,编译后的代码的运行时内存区域)3、在内存中生... 查看详情

jvm之java类加载机制和类加载器(classloader)的详解

当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化。  &nb... 查看详情

描述一下jvm加载class文件的原理机制?

...和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。由于Java的跨平台性,经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件。当Java程序需要使... 查看详情

描述一下jvm加载class文件的原理机制?

...和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。由于Java的跨平台性,经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件。当Java程序需要使... 查看详情

jvm面试题,看这篇就足够了(87题详解)

...制19、GC是什么?为什么要有GC?20、堆(Heap-线程共享)-运行时数据区21、方法区/永久代(线程共享)22、JVM运行时内存23、新生代24、老年代25、永久代26、JAVA8与元数据27、引用计数法28、可达性分析29、标记清除算法(Mark-Sweep)... 查看详情

jvm面试题,看这篇就足够了(87题详解)

...制19、GC是什么?为什么要有GC?20、堆(Heap-线程共享)-运行时数据区21、方法区/永久代(线程共享)22、JVM运行时内存23、新生代24、老年代25、永久代26、JAVA8与元数据27、引用计数法28、可达性分析29、标记清除算法(Mark-Sweep)... 查看详情

java面试--jvm类加载

...流2、将这个类字节流代表的静态存储结构转为方法区的运行时数据结构在堆中生成一个代表此类的java.lang.Class对象,作为访 查看详情

java——jvm内存详解(代码片段)

1.简介Java程序运行时,需要在内存中分配空间。为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。分配:通过关键字new创建对象分配内存空间,... 查看详情

java反射机制详解(代码片段)

...将在下一篇文章中介绍反射的介绍反射(Reflection)是Java在运行时(Runtime)可以访问、检测和修改它本身状态或行为的一种能力,它允许运行中的Java程序获取自身的信息,并且可以操作类或对象的内部属性。Class类介绍:Java虚拟机... 查看详情

java虚拟机详解02----jvm内存结构(代码片段)

...要内容如下:JVM启动流程JVM基本结构内存模型编译和解释运行的概念 一、JVM启动流程:JVM启动时,是由java命令/javaw命令来启动的。二、JVM基本结构:JVM基本结构图:《深入理解Java虚拟机(第二版)》中的描述是下面这个样... 查看详情

运行机制和jvm

...负责解释执行字节码文件的是Java虚拟机,即JVM。JVM是可运行Java字节码文件的虚拟计算机。所有平台上的JVM向编译器提供相同的编程接口,而编译器只需要面向虚拟机,生成虚拟机理解的代码,然后由虚拟机来解释执行。在一些... 查看详情

java程序运行机制

目录Java程序运行机制运行过程注释JDK,JRE,JVM第一个JAVA程序java命名规范入门小游戏Java程序运行机制运行过程源文件(a.java)Java编译器字节码文件(a.class)进入JRE,分别执行类装载器-->字节码校验器-->解释器系统平台,执行.注释JRE中... 查看详情

jvm及垃圾回收机制原理

JVMJava虚拟机Java虚拟机(Javavirtualmachine,JVM)是运行Java程序必不可少的机制。JVM实现了Java语言最重要的特征:即平台无关性。原理:编译后的Java程序指令并不直接在硬件系统的CPU上执行,而是由JVM执行。JVM屏蔽了与具体平台相... 查看详情

java面试题之java类加载机制详解!

Java类加载机制详解【java面试题】(1)问题分析:Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许... 查看详情

jvm类加载机制

...在Java语言里面,类型的加载、连接、初始化、过程都在运行期间完成,11 查看详情