欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    关于Java虚拟机.pdf

    • 资源ID:76247493       资源大小:63.42KB        全文页数:13页
    • 资源格式: PDF        下载积分:20金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要20金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    关于Java虚拟机.pdf

    一、什么是 Java 虚拟机当你谈到 Java 虚拟机时,你可能是指:1、抽象的 Java 虚拟机规范2、一个具体的 Java 虚拟机实现3、一个运行的 Java 虚拟机实例二、Java 虚拟机的生命周期一个运行中的 Java 虚拟机有着一个清晰的任务:执行 Java 程序。程序开始执行时他才运行,程序结束时他就停止。你在同一台机器上运行三个程序,就会有三个运行中的 Java 虚拟机。Java 虚拟机总是开始于一个main()方法,这个方法必须是公有、返回 void、直接受一个字符串数组。在程序执行时,你必须给 Java 虚拟机指明这个包换main()方法的类名。Main()方法是程序的起点,他被执行的线程初始化为程序的初始线程。程序中其他的线程都由他来启动。Java 中的线程分为两种:守护线程(daemon)和普通线程(non-daemon)。守护线程是Java 虚拟机自己使用的线程,比如负责垃圾收集的线程就是一个守护线程。当然,你也可以把自己的程序设置为守护线程。包含 Main()方法的初始线程不是守护线程。只要 Java 虚拟机中还有普通的线程在执行,Java 虚拟机就不会停止。如果有足够的权限,你可以调用exit()方法终止程序。三、Java 虚拟机的体系结构在 Java 虚拟机的规范中定义了一系列的子系统、内存区域、数据类型和使用指南。这些组件构成了Java 虚拟机的内部结构,他们不仅仅为 Java 虚拟机的实现提供了清晰的内部结构,更是严格规定了Java 虚拟机实现的外部行为。每一个 Java 虚拟机都由一个类加载器子系统(classloadersubsystem),负责加载程序中的类型(类和接口),并赋予唯一的名字。每一个Java 虚拟机都有一个执行引擎(executionengine)负责执行被加载类中包含的指令。程序的执行需要一定的内存空间,如字节码、被加载类的其他额外信息、程序中的对象、方法的参数、返回值、本地变量、处理的中间变量等等。Java 虚拟机将 这些信息统统保存在数据区(data areas)中。虽然每个 Java 虚拟机的实现中都包含数据区,但是Java 虚拟机规范对数据区的规定却非常的抽象。许多结构上的细节部分都留给了Java 虚拟机实现者自己发挥。不同Java 虚拟机实现上的内存结构千差万别。一部分实现可能占用很多内存,而其他以下可能只占用很少的内存;一些实现可能会使用虚拟内存,而其他的则不使用。这种比较精炼的 Java 虚拟机内存规约,可以使得 Java 虚拟机可以在广泛的平台上被实现。数据区中的一部分是整个程序共有,其他部分被单独的线程控制。每一个Java 虚拟机都包含方法区(method area)和堆(heap),他们都被整个程序共享。Java 虚拟机加载并解析一个类以后,将从类文件中解析出来的信息保存与方法区中。程序执行时创建的对象都保存在堆中。当一个线程被创建时,会被分配只属于他自己的PC寄存器“pc register”(程序计数器)和Java 堆栈(Java stack)。当线程不掉用本地方法时,PC寄存器中保存线程执行的下一条指令。Java 堆栈保存了一个线程调用方法时的状态,包括本地变量、调用方法的参数、返回值、处理的中间变量。调用本地方法时的状态保存在本地方法堆栈中(nativemethod stacks),可能再寄存器或者其他非平台独立的内存中。Java 堆栈有堆栈块(stackframes(or frames)组成。堆栈块包含 Java方法调用的状态。当一个线程调用一个方法时,Java 虚拟机会将一个新的块压到 Java 堆栈中,当这个方法运行结束时,Java 虚拟机会将对应的块弹出并抛弃。Java 虚拟机不使用寄存器保存计算的中间结果,而是用Java 堆栈在存放中间结果。这是的 Java 虚拟机的指令更紧凑,也更容易在一个没有寄存器的设备上实现 Java 虚拟机。图中的 Java 堆栈中向下增长的,PC寄存器中线程三为灰色,是因为它正在执行本地方法,他的下一条执行指令不保存在PC寄存器中。四、数据类型(Data Types)所有 Java 虚拟机中使用的数据都有确定的数据类型,数据类型和操作都在Java 虚拟机规范中严格定义。Java 中的数据类型分为原始数据类型(primitivetypes)和引用数据类型(referencetype)。引用类型依赖于实际的对象,但不是对象本身。原始数据类型不依赖于任何东西,他们就是本身表示的数据。所有 Java 程序语言中的原始数据类型,都是 Java 虚拟机的原始数据类型,除了布尔型(boolean)。当编译器将Java 源代码编译为自己码时,使用整型(int)或者字节型(byte)去表示布尔型。在Java 虚拟机中使用整数0 表示布尔型的 false,使用非零整数表示布尔型的true,布尔数组被表示为字节数组,虽然他 们可能会以字节数组或者字节块(bitfields)保存在堆中。除了布尔型,其他Java 语言中的原始类型都是Java 虚拟机中的数据类型。在 Java 中数据类型被分为:整形的byte,short,int,long;char 和浮点型的float,double.Java 语言中的数据类型在任何主机上都有同样的范围。本页已使用福昕阅读器进行编辑。福昕软件(),版权所有,仅供试用。在Java 虚拟机中还存在一个Java 语言中不能使用的原始数据类型返回值类型(returnValue)。这种类型被用来实现Java 程序中的“finallyclauses”,具体的参见 18 章的“FinallyClauses”。引用类型可能被创建为:类类型(classtype),接口类型(interfacetype),数组类型(arraytype)。他们都引用被动态创建的对象。当引用类型引用 null时,说明没有引用任何对象。Java 虚拟机规范只定义了每一种数据类型表示的范围,没有定义在存储时每种类型占用的空间。他们如何存储由Java 虚拟机的实现者自己决定。关于浮点型更多信息参见14 章“FloatingPointArithmetic”。五、字节长度Java 虚拟机中最小的数据单元式字(word),其大小由 Java 虚拟机的实现者定义。但是一个字的大小必须足够容纳byte,short,int,char,float,returnValue,reference;两个字必须足够容纳long,double.所以虚拟机的实现者至少提供的字不能小于 31bits的字,但是最好选择特定平台上最有效率的字长。在运行时,Java 程序不能决定所运行机器的字长。字长也不会影响程序的行为,他只是在 Java 虚拟机中的一种表现方式。六、类加载器子系统Java 虚拟机中的类加载器分为两种:原始类加载器(primordialclassloader)和类加载器对象(classloaderobjects)。原始类加载器是Java 虚拟机实现的一部分,类加载器对象是运行中的程序的一部分。不同类加载器加载的类被不同的命名空间所分割。TypeRangebyte8-bitsignedtwoscomplement integer(-27to 27-1,inclusive)short16-bitsigned twoscomplement integer(-215to 215-1,inclusive)int32-bitsignedtwoscomplement integer(-231to 231-1,inclusive)long64-bitsignedtwoscomplement integer(-263to 263-1,inclusive)char16-bitunsigned Unicode character(0 to 216-1,inclusive)float32-bitIEEE 754 single-precisionfloatdouble64-bitIEEE 754 double-precisionfloatreturnValueaddressof an opcode withinthe same methodreferencereferenceto an objecton the heap,or null本页已使用福昕阅读器进行编辑。福昕软件(),版权所有,仅供试用。类加载器调用了许多 Java 虚拟机中其他的部分和java.lang包中的很多类。比如,类加载对象就是java.lang.ClassLoader子类 的实例,ClassLoader 类中的方法可以访问虚拟机中的类加载机制;每一个被Java 虚拟机加载的类都会被表示为一个java.lang.Class类的实例。像其他对象一样,类加载器对象和Class 对象都保存在堆中,被加载的信息被保存在方法区中。1、加载、连接、初始化(Loading,Linkingand Initialization)类加载子系统不仅仅负责定位并加载类文件,他按照以下严格的步骤作了很多其他的事情:(具体的信息参见第七章的“类的生命周期”)1)、加载:寻找并导入指定类型(类和接口)的二进制信息2)、连接:进行验证、准备和解析验证:确保导入类型的正确性准备:为类型分配内存并初始化为默认值解析:将字符引用解析为直接饮用3)、初始化:调用Java 代码,初始化类变量为合适的值2、原始类加载器(The PrimordialClass Loader)每个 Java 虚拟机都必须实现一个原始类加载器,他能够加载那些遵守类文件格式并且被信任的类。但是,Java虚拟机的规范并没有定义如何加载类,这由 Java 虚拟机实现者自己决定。对于给定类型名的类型,原始莱加载器必须找到那个类型名加“。class”的文件并加载入虚拟机中。3、类加载器对象虽然类加载器对象是Java 程序的一部分,但是ClassLoader 类中的三个方法可以访问 Java 虚拟机中的类加载子系统。1)、protectedfinalClass defineClass():使用这个方法可以出入一个字节数组,定义一个新的类型。2)、protectedClass findSystemClass(Stringname):加载指定的类,如果已经加载,就直接返回。3)、protectedfinalvoidresolveClass(Class c):defineClass()方法只是加载一个类,这个方法负责后续的动态连接和初始化。具体的信息,参见第八章“连接模型”(The LinkingModel)。本页已使用福昕阅读器进行编辑。福昕软件(),版权所有,仅供试用。4、命名空间当多个类加载器加载了同一个类时,为了保证他们名字的唯一性,需要在类名前加上加载该类的类加载器的标识。具体的信息,参见第八章“连接模型”(The LinkingModel)。七、方法区(The Method Area)在 Java 虚拟机中,被加载类型的信息都保存在方法区中。这写信息在内存中的组织形式由虚拟机的实现者定义,比如,虚拟机工作在一个“little-endian”的处理器上,他就可以将信息保存为“little-endian”格式的,虽然在 Java 类文件中他们是以“big-endian”格式保存的。设计者可以用最适合并地机器的表示格式来存储数据,以保证程序能够以最快的速度执行。但是,在一个只有很小内存的设备上,虚拟机的实现者就不会占用很大的内存。程序中的所有线程共享一个方法区,所以访问方法区信息的方法必须是线程安全的。如果你有两个线程都去加载一个叫Lava 的类,那只能由一个线程被容许去加载这个类,另一个必须等待。在程序运行时,方法区的大小是可变的,程序在运行时可以扩展。有些 Java虚拟机的实现也可以通过参数也订制方法区的初始大小,最小值和最大值。方法区也可以被垃圾收集。因为程序中的内由类加载器动态加载,所有类可能变成没有被引用(unreferenced)的状态。当类变成这种状态时,他就可 能被垃圾收集掉。没有加载的类包括两种状态,一种是真正的没有加载,另一个种是“unreferenced”的状态。详细信息参见第七章的类的生命周期(TheLifetimeof a Class)。1、类型信息(Type Information)每一个被加载的类型,在Java 虚拟机中都会在方法区中保存如下信息:1)、类型的全名(The fullyqualifiednameof the type)2)、类型的父类型的全名(除非没有父类型,或者弗雷形式java.lang.Object)(The fullyqualifiednameof the type s directsuperclass)3)、给类型是一个类还是接口(classor an interface)(Whether or notthe type isa class)4)、类型的修饰符(public,private,protected,static,final,volatile,transient等)(The type s modifiers)本页已使用福昕阅读器进行编辑。福昕软件(),版权所有,仅供试用。5)、所有父接口全名的列表(An orderedlistof the fullyqualifiednames of any directsuperinterfaces)类型全名保存的数据结构由虚拟机实现者定义。除此之外,Java 虚拟机还要为每个类型保存如下信息:1)、类型的常量池(The constantpool forthe type)2)、类型字段的信息(Fieldinformation)3)、类型方法的信息(Method information)4)、所有的静态类变量(非常量)信息(Allclass(static)variablesdeclaredinthe type,exceptconstants)5)、一个指向类加载器的引用(Areferenceto classClassLoader)6)、一个指向 Class 类的引用(Areferenceto classClass)1)、类型的常量池(The constantpool forthe type)常量池中保存中所有类型是用的有序的常量集合,包含直接常量(literals)如字符串、整数、浮点数的常量,和对类型、字段、方法的符号引用。常量池 中每一个保存的常量都有一个索引,就像数组中的字段一样。因为常量池中保存中所有类型使用到的类型、字段、方法的字符引用,所以它也是动态连接的主要对象。详细信息参见第六章“The Java Class File”。2)、类型字段的信息(Fieldinformation)字段名、字段类型、字段的修饰符(public,private,protected,static,final,volatile,transient等)、字段在类中定义的顺序。3)、类型方法的信息(Method information)方法名、方法的返回值类型(或者是void)、方法参数的个数、类型和他们的顺序、字段的修饰符(public,private,protected,static,final,volatile,transient等)、方法在类中定义的顺序如果不是抽象和本地本法还需要保存方法的字节码、方法的操作数堆栈的大小和本地变量区的大小(稍候有详细信息)、异常列表(详细信息参见第十七章“Exceptions”。)4)、类(静态)变量(Class Variables)类变量被所有类的实例共享,即使不通过类的实例也可以访问。这些变量绑定在类上(而不是类的实例上),所以他们是类的逻辑数据的一部分。在Java虚拟机使用这个类之前就需要为类变量(non-final)分配内存本页已使用福昕阅读器进行编辑。福昕软件(),版权所有,仅供试用。常量(final)的处理方式于这种类变量(non-final)不一样。每一个类型在用到一个常量的时候,都会复制一份到自己的常量池中。常 量也像类变量一样保存在方法区中,只不过他保存在常量池中。(可能是,类变量被所有实例共享,而常量池是每个实例独有的)。Non-final类变量保存为定义他的类型数据(data forthe typethatdeclaresthem)的一部分,而 final常量保存为使用他的类型数据(data forany typethatuses them)的一部分。详情参见第六章“The Java Class FileTheJava Class File”5)、指向类加载器的引用(Areferenceto classClassLoader)每一个被 Java 虚拟机加载的类型,虚拟机必须保存这个类型是否由原始类加载器或者类加载器加载。那些被类加载器加载的类型必须保存一个指向类加载器的引用。当类加载器动态连接时,会使用这条信息。当一个类引用另一个类时,虚拟机必须保存那个被引用的类型是被同一个类加载器加载的,这也是虚拟机维护不同命名空间的过程。详情参见第八章“The LinkingModel”6)、指向 Class 类的引用(Areferenceto classClass)Java 虚拟机为每一个加载的类型创建一个java.lang.Class类的实例。你也可以通过 Class 类的方法:publicstaticClass forName(StringclassName)来查找或者加载一个类,并取得相应的 Class 类的实例。通过这个 Class 类的实例,我们可以访问 Java虚拟机方法区中的信息。具体参照Class 类的 JavaDoc.2、方法列表(Method Tables)为了更有效的访问所有保存在方法区中的数据,这些数据的存储结构必须经过仔细的设计。所有方法区中,除了保存了上边的那些原始信息外,还有一个 为了加快存取速度而设计的数据结构,比如方法列表。每一个被加载的非抽象类,Java 虚拟机都会为他们产生一个方法列表,这个列表中保存了这个类可能调用的所有实例方法的引用,报错那些父类中调用的方法。详情参见第八章“TheLinkingModel”八、堆当 Java 程序创建一个类的实例或者数组时,都在堆中为新的对象分配内存。虚拟机中只有一个堆,所有的线程都共享他。1、垃圾收集(Garbage Collection)垃圾收集是释放没有被引用的对象的主要方法。它也可能会为了减少堆的碎片,而移动对象。在Java 虚拟机的规范中没有严格定义垃圾收集,只是定义一个 Java 虚拟机的实现必须通过某种方式管理自己的堆。详情参见第九章“Garbage Collection”。本页已使用福昕阅读器进行编辑。福昕软件(),版权所有,仅供试用。2、对象存储结构(ObjectRepresentation)Java 虚拟机的规范中没有定义对象怎样在堆中存储。每一个对象主要存储的是他的类和父类中定义的对象变量。对于给定的对象的引用,虚拟机必须嫩耨很快的定位到这个对象的数据。另为,必须提供一种通过对象的引用方法对象数据的方法,比如方法区中的对象的引用,所以一个对象保存的数据中往往含有一个某种形式指向方法区的指针。一个可能的堆的设计是将堆分为两个部分:引用池和对象池。一个对象的引用就是指向引用池的本地指针。每一个引用池中的条目都包含两个部分:指向 对象池中对象数据的指针和方法区中对象类数据的指针。这种设计能够方便Java虚拟机堆碎片的整理。当虚拟机在对象池中移动一个对象的时候,只需要修改对应引用池中的指针地址。但是每次访问对象的数据都需要处理两次指针。下图演示了这种堆的设计。在第九章的“垃圾收集”中的HeapOfFish Applet 演示了这种设计。另一种堆的设计是:一个对象的引用就是一个指向一堆数据和指向相应对象的偏移指针。这种设计方便了对象的访问,可是对象的移动要变的异常复杂。下图演示了这种设计当程序试图将一个对象转换为另一种类型时,虚拟机需要判断这种转换是否是这个对象的类型,或者是他的父类型。当程序适用 instanceof语 句的时候也会做类似的事情。当程序调用一个对象的方法时,虚拟机需要进行动态绑定,他必须判断调用哪一个类型的方法。这也需要做上面的判断。无论虚拟机实现者使用哪一种设计,他都可能为每一个对象保存一个类似方法列表的信息。因为他可以提升对象方法调用的速度,对提升虚拟机的性能非常重要,但是虚拟机的规范中比没有要求必须实现类似的数据结构。下图描述了这种结构。图中显示了一个对象引用相关联的所有的数据结构,包括:1)、一个指向类型数据的指针2)、一个对象的方法列表。方法列表是一个指向所有可能被调用对象方法的指针数组。方法数据包括三个部分:操作码堆栈的大小和方法堆栈的本地变量区;方法的字节码;异常列表。每一个 Java 虚拟机中的对象必须关联一个用于同步多线程的l ock(mutex)。同一时刻,只能有一个对象拥有这个对象的锁。当一个拥有这个这个对象的锁,他就可以多次申请这个锁,但是也必须释放相应次数的锁才能真正释放这个对象锁。很多对象在整个生命周期中都不会被锁,所以这个信息只有在需要时才需要添加。很多 Java 虚拟机的实现都没有在对象的数据中包含“锁定数据”,只是在需要时才生成相应的数据。除了实现对象的锁定,每一个对象还逻辑关联到一个“waitset”的实现。锁定帮组线程独立处理共享的数据,不需要妨碍其他的线程。“waitset”帮组线程协作完成同一个目标。“waitset”往往通过Object 类的 wait()和 notify()方法来实现。垃圾收集也需要堆中的对象是否被关联的信息。Java 虚拟机规范中指出垃圾收集一个运行一个对象的finalizer方法一次,但是容许finalizer方法重新引用这个对象,当这个对象再次不被引用时,就不需要再次调用finalize方法。所以虚拟机也需要保存finalize方法 是否运行过的信息。更多信息参见第九章的“垃圾收集”3、数组的保存(ArrayRepresentation)在 Java 中,数组是一种完全意义上的对象,他和对象一样保存在堆中、有一个指向 Class 类实例的引用。所有同一维度和类型的数组拥有同样的Class,数组的长度不做考虑。对应Class 的名字表示为维度和类型。比如一个整型数据的 Class 为“I”,字节型三维数组 Class 名为“B”,两维对象数据Class名为“Ljava.lang.Object”。多维数组被表示为数组的数组,如下图:数组必须在堆中保存数组的长度,数组的数据和一些对象数组类型数据的引用。通过一个数组引用的,虚拟机应该能够取得一个数组的长度,通过索引能够访问特定的数据,能够调用Object 定义的方法。Object 是所有数据类的直接父类。更多信息参见第六章“类文件”。九、PC寄存器(程序计数器)(The Program Counter)每一个线程开始执行时都会被创建一个程序计数器。程序计数器只有一个字长(word),所以它能够保存一个本地指针和returnValue.当线程执行时,程序计数器中存放了正在执行指令的地址,这个地址可以使一个本地指针,也可以使一个从方法字节码开始的偏移指针。如果执行本地方法,程序计数器的值没有被定义。十、Java 堆栈(The Java Stack)当一个线程启动时,Java 虚拟机会为他创建一个Java 堆栈。Java 堆栈用一些离散的 frame 类纪录线程的状态。Java 虚拟机堆 Java 堆栈的操作只有两种:压入和弹出 frames.线程中正在执行的方法被称为当前方法(currentmethod),当前方法所对应的 frame 被称为当前帧(currentframe)。定义当前方法的类被称为当前类(currentclass),当前类的常量池被称为当前常量池(currentconstantpool.)。当线程执行时,Java 虚拟机会跟踪当前类和当前常量池。但线程操作保存在帧中的数据时,他只操作当前帧的数据。当线程调用一个方法时,虚拟机会生成一个新的帧,并压入线程的Java 堆栈。这个新的帧变成当前帧。当方法执行时,他使用当前帧保存方法的参数、本地变 量、中间结构和其他数据。方法有两种退出方式:正常退出和异常推出。无论方法以哪一种方式推出,Java 虚拟机都会弹出并丢弃方法的帧,上一个方法的帧变为当前帧。所有保存在帧中的数据都只能被拥有它的线程访问,线程不能访问其他线程的堆栈中的数据。所以,访问方法的本地变量时,不需要考虑多线程同步。和方法区、堆一样,Java 堆栈不需要连续的内存空间,它可以被保存在一个分散的内存空间或者堆上。堆栈具体的数据和长度都有Java 虚拟机的实现者自己定义。一些实现可能提供了执行堆栈最大值和最小值的方法。十一、堆栈帧(The Stack Frame)堆栈帧包含三部分:本地变量、操作数堆栈和帧数据。本地变量和操作数堆栈的大小都是一字(word)为单位的,他们在编译就已经确定。帧数据的大小取决于 不同的实现。当程序调用一个方法时,虚拟机从类数据中取得本地变量和操作数堆栈的大小,创建一个合适大小和帧,然后压入Java 堆栈中。1、本地变量(LocalVariables)本地变量在 Java 堆栈帧中被组织为一个从0 计数的数组,指令通过提供他们的索引从本地变量区中取得相应的值。Int,float,reference,returnValue占一个字,byte,short,char 被转换成 int 然后存储,long 和 doubel 占两个字。指令通过提供两个字索引中的前一个来取得long,doubel 的值。比如一个long 的值存储在索引3,4 上,指令就可以通过3 来取得这个 long 类型的值。本地变量区中包含了方法的参数和本地变量。编译器将方法的参数以他们申明的顺序放在数组的前面。但是编译器却可以将本地变量任意排列在本地变量数组中,甚至两个本地变量可以公用一个地址,比如,当两个本地变量在两个不交叠的区域内,就像循环变量i,j.虚拟机的实现者可以使用任何结构来描述本地变量区中的数据,虚拟机规范中没有定义如何存储long 和 doubel.2、操作数堆栈(Operand Stack)向本地变量一样,操作数堆栈也被组织为一个以字为单位的数组。但是不像本地变量那样通过索引访问,而是通过push 和 pop 值来实现访问的。如果一个指令 push 一个值到堆栈中,那么下一个指令就可以pop 并且使用这个值。操作数堆栈不像程序计数器那样不可以被指令直接访问,指令可以直接访问操作数堆栈。Java 虚拟机是一个以堆栈为基础,而不是以寄存器为基础的,因为它的 指令从堆栈中取得操作数,而不是同寄存器中。当然,指令也可以从其他地方去的操作数,比如指令后面的操作码,或者常量池。但是Java 虚拟机指令主要是从操作数堆栈中取得他们需要的操作数。Java 虚拟机将操作数堆栈视为工作区,很多指令通过先从操作数堆栈中pop值,在处理完以后再将结果push 回操作数堆栈。一个 add 的指令 执行过程如下图所示:先执行 iload_0 和 iload_1 两条指令将需要相加的两个数,从本地方法区中取出,并 push 到操作数堆栈中;然后执行iadd 指令,现pop 出两个值,相加,并将结果 pusp 进操作数堆栈中;最后执行istore_2指令,pop 出结果,赋值到本地方法区中。3、帧数据(Frame Data)处理本地变量和操作数堆栈以外,java 堆栈帧还包括了为了支持常量池,方法返回值和异常分发需要的数据,他们被保存在帧数据中。当虚拟机遇到使用指向常量池引用的指令时,就会通过帧数据中指向常量区的指针来访问所需要的信息。前面提到过,常量区中的引用在最开始时都是符号引用。即使当虚拟机检查这些引用时,他们也是字符引用。所以虚拟机需要在这时转换这个引用。当一个方法正常返回时,虚拟机需要重建那个调用这个方法的方法的堆栈帧。如果执行完的方法有返回值,虚拟机就需要将这个值push 进调用方法的哪个操作数堆栈中。帧数据中也包含虚拟机用来处理异常的异常表的引用。异常表定义了一个被catch 语句保护的一段字节码。每一个异常表中的个体又包含了需要保护的字节玛的 范围,和异常被捕捉到时需要执行的字节码的位置。当一个方法抛出一个异常时,Java 虚拟机就是用异常表去判断如何处理这个异常。如果虚拟机找到了一个匹配的 catch,他就会将控制权交给catch 语句。如果没有找到匹配的 catch,方法就会异常返回,然后再调用的方法中继续这个过程。除了以上的三个用途外,帧数据还可能包含一些依赖于实现的数据,比如调试的信息。十二、本地方法堆栈本地方法区依赖于虚拟机的不同实现。虚拟机的实现者可以自己决定使用哪一种机制去执行本地方法。任何本地方法接口(NativeMethod Interface)都使用某种形式的本地方法堆栈。十三、执行引擎一个 java 虚拟机实现的核心就是执行引擎。在 Java 虚拟机规范,执行引擎被描述为一系列的指令。对于每一个指令,规范都描述了他们应该做什么,但是没有说要如何去做。1、指令集在 Java 虚拟机中一个方法的字节码流就是一个指令的序列。每一个指令由一个字节的操作码(Opcode)和可能存在的操作数(Operands)。操作 码指示去做什么,操作数提供一些执行这个操作码可能需要的额外的信息。一个抽象的执行引擎每次执行一个指令。这个过程发生在每一个执行的线程中。有时,执行引擎可能会遇到一个需要调用本地方法的指令,在这种情况下,执行引擎会去试图调用本地方法,但本地方法返回时,执行引擎会继续执行字节码流中的下一个指令。本地方法也可以看成对Java 虚拟机中的指令集的一种扩充。决定下一步执行那一条指令也是执行引擎工作的一部分。执行引擎有三种方法去取得下一条指令。多数指令会执行跟在他会面的指令;一些像 goto,return的指令,会在他们执行的时候决定他们的下一条指令;当一个指令抛出异常时,执行引擎通过匹配catch 语句来决定下一条应该执行的指令。平台独立性、网络移动性、安全性左右了 Java 虚拟机指令集的设计。平台独立性是指令集设计的主要影响因素之一。基于堆栈的结构使得Java 虚拟机可以在 更多的平台上实现。更小的操作码,紧凑的结构使得字节码可以更有效的利用网络带宽。一次性的字节码验证,使得字节码更安全,而不影响太多的性能。2、执行技术许多种执行技术可以用在Java 虚拟机的实现中:解释执行,及时编译(just-in-timecompiling),hot-spotcompiling,nativeexecutioninsilicon.3、线程Java 虚拟机规范定义了一种为了在更多平台上实现的线程模型。Java 线程模型的一个目标时可以利用本地线程。利用本地线程可以让Java 程序中的线程能过在多处理器机器上真正的同时执行。Java 线程模型的一个代价就是线程优先级,一个Java 线程可以在 1-10 的优先级上运行。1 最低,10最高。如果设计者使用了本地线程,他 们可能将这10个优先级映射到本地优先级上。Java 虚拟机规范只定义了,高一点优先级的线程可以却一些 cpu 时间,低优先级的线程在所有高优先级线程都堵塞时,也可以获取一些 cpu 时间,但是这没有保证:低优先级的线程在高优先级线程没有堵塞时不可以获得一定的cpu 时间。因此,如果需要在不同的线程间协作,你必 须使用的“同步(synchronizatoin)”。同步意味着两个部分:对象锁(objectlocking)和线程等待、激活(threadwaitand notify)。对象锁帮助线程可以不受其他线程的干扰。线程等待、激活可以让不同的线程进行协作。在 Java 虚拟机的规范中,Java 线程被描述为变量、主内存、工作内存。每一个 Java 虚拟机的实例都有一个主内存,他包含了所有程序的变量:对象、数组合类变量。每一个线程都有自己的工作内存,他保存了哪些他可能用到的变量的拷贝。规则:1)、从主内存拷贝变量的值到工作内存中2)、将工作内存中的值写会主内存中如果一个变量没有被同步化,线程可能以任何顺序更新主内存中的变量。为了保证多线程程序的正确的执行,必须使用同步机制。十四、本地方法接口(NativeMethod Interface)Java 虚拟机的实现并不是必须实现本地方法接口。一些实现可能根本不支持本地方法接口。Sun的本地方法接口是JNI(Java NativeInterface)。

    注意事项

    本文(关于Java虚拟机.pdf)为本站会员(索****)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开