java虚拟机结构机制Word文件下载.docx

上传人:b****1 文档编号:3400177 上传时间:2023-05-01 格式:DOCX 页数:19 大小:479.52KB
下载 相关 举报
java虚拟机结构机制Word文件下载.docx_第1页
第1页 / 共19页
java虚拟机结构机制Word文件下载.docx_第2页
第2页 / 共19页
java虚拟机结构机制Word文件下载.docx_第3页
第3页 / 共19页
java虚拟机结构机制Word文件下载.docx_第4页
第4页 / 共19页
java虚拟机结构机制Word文件下载.docx_第5页
第5页 / 共19页
java虚拟机结构机制Word文件下载.docx_第6页
第6页 / 共19页
java虚拟机结构机制Word文件下载.docx_第7页
第7页 / 共19页
java虚拟机结构机制Word文件下载.docx_第8页
第8页 / 共19页
java虚拟机结构机制Word文件下载.docx_第9页
第9页 / 共19页
java虚拟机结构机制Word文件下载.docx_第10页
第10页 / 共19页
java虚拟机结构机制Word文件下载.docx_第11页
第11页 / 共19页
java虚拟机结构机制Word文件下载.docx_第12页
第12页 / 共19页
java虚拟机结构机制Word文件下载.docx_第13页
第13页 / 共19页
java虚拟机结构机制Word文件下载.docx_第14页
第14页 / 共19页
java虚拟机结构机制Word文件下载.docx_第15页
第15页 / 共19页
java虚拟机结构机制Word文件下载.docx_第16页
第16页 / 共19页
java虚拟机结构机制Word文件下载.docx_第17页
第17页 / 共19页
java虚拟机结构机制Word文件下载.docx_第18页
第18页 / 共19页
java虚拟机结构机制Word文件下载.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

java虚拟机结构机制Word文件下载.docx

《java虚拟机结构机制Word文件下载.docx》由会员分享,可在线阅读,更多相关《java虚拟机结构机制Word文件下载.docx(19页珍藏版)》请在冰点文库上搜索。

java虚拟机结构机制Word文件下载.docx

这次检查,class文件检验器不需要查看字节码,也不需要查看和装载任何其他类型。

在这趟扫描中,检验器查看每个组成部分,确认它们是否是其所属类型的实例,它们结构是否正确。

还会检查这个类本身是否符合特定的条件,它们是由java编程语言规定的。

比如,除Object外,所有类都必须要有一个超类,final的类不能被子类化,final方法也没有被覆盖,检查常量池中的条目是合法的,而且常量池的所有索引必须指向正确类型的常量池条目。

3.检查字节码是否导致JVM崩溃

字节码流代表了java的方法,它是由被称为操作码的单字节指令组成的序列,每一个操作码后都跟着一个或多个操作数。

执行字节码时,依次执行操作码,这就在java虚拟机内构成了执行的线程,每一个线程被授予自己的java栈,这个栈是由不同的栈帧构成的,每一个方法调用将获得一个自己的栈帧——栈帧其实就是一个内存片段,其中存储着局部变量和计算的中间结果,用于存储中间结果的部分被称为操作数栈。

字节码检验器要进行大量的检查,以确保采用任何路径在字节码流中都得到一个确定的操作码,确保操作数栈总是包含正确的数值以及正确的类型。

它必须保证局部变量在赋予合适的值以前不能被访问,而且类的字段中必须总是被赋予正确类型的值,类的方法被调用时总是传递正确数值和类型的参数。

字节码检验器还必须保证每个操作码都是合法的,即都有合法的操作数,以及对每一个操作码,合适类型的数值位于局部变量中或是在操作数栈中。

这些仅仅是字节码检验器所做的大量检验工作中的一小部分,在整个检验过程通过后,它就能保证这个字节码流可以被java虚拟机安全的执行。

4.检查符号引用验证

第四趟扫描可能紧随第三趟扫描发生,也有可能在第三趟扫描之后很久,当字节码被执行时才执行。

动态连接是一个将符号引用解析为直接引用的过程。

当java虚拟机执行字节码时,如果它遇到一个操作码,这个操作码第一次使用一个指向另一个类的符号引用,那么虚拟机就必须解析这个符号引用。

在解析时,虚拟机执行两个基本任务:

——查找被引用的类(如果必要的话就装载它)

——将符号引用替换为直接引用,例如指向一个类、字段或方法的指针或偏移量

虚拟机必须记住这个直接引用,这样当它以后再次遇到同样的引用时,就可以直接使用,而不需要重新解析该符号引用了。

步骤三:

内置于JVM的安全特性

步骤四:

安全管理器SecurityManager

步骤五:

java签名/证书机制

JVM的内部组成结构

由6个部分组成:

1.解释器

2.指令系统

3.寄存器

4.JVM栈

5.存储区

6.碎片回收区

 

JVM的执行引擎有以下几种:

1.一次性解释字节码

2.即时编译器(just–in–timecompiler),这种情况一,第一次执行的字节码会被编译成本地机器代码,编译出的本地机器代码会被缓存,当方法以后被调用时可以重用。

3.自适应优化器,JVM开始时解释字节码,但是会监视运行中有出入活动,并且记录下使用最频繁的代码段。

程序运行时候,将最频繁的代码编译成本地代码

JVM的基本结构图

字节码

一个Java应用程序可以使用两种类装载器:

bootstrap–启动类装载器和用户定义的类装载器。

Java应用程序能够在运行时安装用户定义的类装载器,这种类装载器能够使用自定义的方式来装载类,例如,从网络下载class文件。

类装载器在装载class文件时还做了些什么呢?

每个类被装载的时候,JVM都监视这个类,看它到底是被启动类装载器还是被用户定义类装载器加载。

当被装载的类引用了另外一个类时,JVM就会使用装载第一个类的类装载器装载被引用的类。

所以被装载的类默认情况下只能看到被同一个类装载器装载的别的类。

运行时的Java程序中的每个类装载器都有它自己的命名空间。

在一个Java应用程序能够从一个类或者多个类中实例化多个用户定义的类装载器。

因此,需要多少个都可以创建。

被不同的类装载器装载的类存放在不同的命名空间中,它们不能相互访问,除非应用程序显式地允许这样做。

当编写一个Java应用程序的时候,从不同源文件装载的类可以分隔在不同的命名空间中。

通过这种方法,就能够使用Java类装载器的体系结构来控制任何从不同源文件中装载的代码之间的相互影响,特别是能够阻止恶意代码获取访问和破坏善意代码的权限。

这就是Java安全的机制之一。

Javaclass文件主要在平台无关性和网络移动性方面使java更适应于网络。

它在平台无关性方面的任务是:

为java程序提供独立于底层主机平台的二进制形式的服务,这正是jvm所期望实现的。

这种途径打破了C或C++等语言所遵循的传统,使用这些传统语言定的程序通常首先被编译,然后被连接成为单独的、专门支持特定硬件平台和操作系统的二进制文件。

通常情况下,一个平台上的二进制可执行文件不能在其他平台上工作。

而javaclass文件是可以运行在任何支持jvm的硬件平台和操作系统上的二进制文件。

二进制文件包含了目标处理器的机器语言,而java编译器把源文件的指令翻译成字节码,这种字节码就是JVM的机器语言。

与C++不同,在Java中,没有通过使用强制转换指针类型或者通过进行指针运算直接访问内存的方法。

在Java中使用对象时,需要严格地遵守类型规则。

Java避免无意间破坏内在的另一个办法是自动垃圾收集。

在Java中,只需要停止对一个对象的引用,一段时间后,垃圾收集器会自动回收这个对象所占据的内存。

垃圾收集器禁止Java程序员显式指明哪个对象应该被释放。

Java在运行时保护内存完整性的第三个办法是数组边界检查。

当操作数组的大于数组的大小时Java会抛出一个异常。

最后一个确保程序健壮性的例子是对对象引用的检查,每次使用引用的时候,为了确保这些引用不为空值,使用一个空的引用时导致一个异常被抛出。

2010-6-8阅录

第二章Java安全

一、基本沙箱

组成沙箱的基本组件:

1.类装载器结构

2.Class文件检验器

3.内置于JVM的安全特性

4.安全管理器及JavaAPI

Java沙箱安全模型,最重要的优点之一就是这些组件中的类装载器和安全管理器是可以由用户定制的,这样可以为Java程序创建个性化的安全策略。

但由于这些内容是非常复杂,定制也要代价也可能存在产生错误,从而开启安全漏洞。

二、类装载器体系结构

类装载器体系结构是第一道防线,从三方面对java的沙箱起作用:

1.防止恶意代码去干涉善意的代码。

2.守护了被信任的类库边界。

3.将代码归入某类,该类确定了代码可以进行哪些操作

Java虚拟机

Java虚拟机—为何称为“虚拟”:

就是因为它仅仅是一个规范来定义的抽象计算机。

因此要运行一个java程序,首先需要一个符合该规范的具体实现。

Java虚拟机,指如下三种东西:

1.抽象规范

2.一个具体的实现

3.一个运行中的虚拟机实现

Java虚拟机的生命周期

JVM职责:

负责运行一个java程序,当启动一个java程序时,一个虚拟机实现也就诞生了,当程序关闭退出,这个虚拟机实现也就随之消亡。

在Java虚拟机内部有两种线程:

守护线程和非守护线程。

守护线程通常是JVM自己使用,如垃圾收集任务的线程,JVM实例可自动退出。

JVM实例行为是分别按照1.子系统、2.内存区、3.数据类型及、4.指令几个术语来描述;

这些展示了抽象的虚拟机的内部抽象体系结构。

JVM的体系结构:

JVM包括在规范中描述的主要子系统和内存区,每个JVM都有一个类装载器子系统,它根据给定的全限定名来装入类型(类或接口);

同样每个JVM还有一个执行引擎,它负责执行那些包含在被装载类的方法中的指令。

运行时数据区

JVM在运行一个程序时,需要内存来存储许多东西,如:

字节码、从已加载的class文件中得到其他信息,程序创建的对象、参数、返回值、局部变量及运算过程中的中间结果等;

JVM都将把这些东西统一放到“运行时数据区”中,便于管理,但这些运行时数据区都会以某种形式存在于JVM中,但规范对它的描述是相当抽象的;

运行时数据区结构上的细节,大多数都由具体实现的设计者决定,这样就具有不同的内存限制,有的可能有大量的内存使用,有的可能只有很少。

有的实现可以利用虚拟内存,但有的就不行。

某些运行时数据区是由程序中所有线程共享,而一些只能由一个线程拥有。

每个JVM实例都有一个方法区以及一个堆,它们是由JVM实例中所有线程共享的,当JVM装载一个class文件时,它会从这个class文件包含的二进制数据中解析类型信息。

然后,把这些类型信息放到方法区中。

当程序运行时,JVM会把所有该程序在运行时创建的对象都放到堆中。

Java栈是由许多栈帧(stackframe)或者说帧(frame)组成,一个栈帧包含一个java方法调用的状态。

当线程调用一个java方法时,JVM压入一个新的栈帧到该线程的java栈中;

当该方法返回时,这个栈帧被从java栈中弹出并抛弃。

JVM没有寄存器,其指令集使用Java栈来存储中间数据。

这样是为了保持JVM的指令集尽量紧凑。

另外这种基于栈的体系结构,也有助于运行时某些虚拟机实现的动态编译器和即时编译器的代码优化。

线程专有的运行时数据区

Java数据类型:

其中boolean值有点特别,当编译器把Java源码编译为字节码时,它会用int或byte来表示。

False用零来表示、所有非零整数都表示true。

而boolean数组当做byte数组来访问,但是在“堆”区,它也可以被表示为位域。

JVM中还有一个只在内部使用的基本类型:

returnAddress,这个基本类型被用来实现java程序中的finally子句。

JVM的引用类型被统称为“引用”(reference),有三种:

类类型、接口类型和数组类型,值都是对动态创建对象的引用。

类类型的值是对类实例的引用;

数组类型的值是对数组对象的引用;

而接口类型的值,对实现了接口的某个类实例的引用。

还有一种特殊的引用值是Null,它表示该引用变量没有引用任何对象。

JVM规范定义了每种数据类型的取值范围,但却没有定义它们的位宽。

存储这些类型的值所需的点位宽度,是由具体的虚拟机的设计者决定的。

类型

范围

byte

8位、带符号,二进制补码(-27~27-1-128—127)包括两端的值在内,占用1字节

short

16位带符号,二进制补码(-215~215-1-32768—32767)包括两端的值在内占用2字节

int

32位带符号,二进制补码(-231~231-1-2147483648-2147483647)包括两端的值在内占用4字节

long

64位,带符号,二进制补码(-263~263-1-2147483648-2147483647)包括两端的值在内,占用8字节

char

16位,不带符号,Unicode字符(0~216-10-127)包括两端的值在内,占用2字节

float

32位,IEEE754标准单精度浮点数

double

64位,IEEE754标准双精度浮点数

boolean

1位

returnAddress

同一方法中某操作码的地址

reference

堆中对某对象的引用,或者是null

字长的考量:

在JVM中最基本的数据单元就是字(word),它的大小是由每个虚拟机实现的设计者来决定,字长必须足够大,至少是一个字单元足以持有byte、short、int、char、float、returnAddress和reference类型的值,而两个字单元就足以持有double和long类型的值。

在JVM规范中,在运行时数据区的大部分内容,都是基于“字”这个抽象概念的。

类装载器子系统:

JVM有两种类装载器:

启动类装载器和用户自定义类装载器,前者是JVM实现的一部分,后者是Java程序的一部分。

由不同的类装载器装载的类将被放到虚拟机内部的不同命名空间中。

类装载子系统涉及JVM的其他几个组成部分,以及几个来自java.lang库的类,比如,用户自定义的类装载器是普通的java对象,它的类必须继承自java.lang.ClassLoader类。

ClassLoader中定义的方法为程序提供了访问类装载器机制的接口。

此外,对于每个被装载的类型,JVM都会为创建一个java.lang.Class类的实例来代表该类型。

和所有其他对象一样,用户自定义的类装载器以及Class类的实例都放在内存中的堆区,而装载的类型信息则都位于方法区。

装载、连接及初始化类装载器子系统除了要定位和导入二进制class文件外,还必须负责验证被导入类的正确性,为类变量分配并初始化内存,以及帮助解析符号引用,这些动作必须严格按以下顺序进行:

1装载——查找并装载类型的二进制数据。

2连接——执行验证,准备,以及解析(可选)。

验证:

确保被导入类型的正确性。

准备:

为类变量分配内存,并将其初始化为默认值。

解析:

把类型中的符号引用转换为直接引用。

3初始化——把类变量初始化为正确初始值。

启动类装载器又是怎样去找到正确的class文件?

只要符合javaclass文件格式的二进制文件,JVM实现都必须能够从中辨别并装载其中的类和接口中。

某些虚拟机实现也可以识别其他的非规范的二进制格式文件,但它必须能够辨别class文件。

每个JVM实现都必须有一个启动类装载器,它知道怎么装载受信任的类。

只要给定某个类型的全限定名,启动类装载器就必须能够以某种方式得到定义该类型的数据。

JDK1.2中,启动类装载器将只在系统类(javaAPI的类文件)的安装路径中查找要装入的类。

而搜索CLASSPATH目录的任务,现在交给了系统类装载器——它是一个自定义的类装载器,虚拟机启动时就被自动创建

用户自定义类装载器:

尽管“用户自定义类装载器”本身是Java程序的一部分,但类ClassLoader中的四个方法是通往JVM的通道:

ProtectedfinalClassdefineClass(Stringname,bytedata[],intoffset,intlength);

protectedfinalClassdefineClass(Stringname,bytedata[],intoffset,intlength,ProtectionDomainprotectionDomain);

protectedfinalClassfindSystemClass(Stringname);

protectedfinalvoidresolveClass(Classc);

两个被重载defineClass()方法都要接受一个名为data[]的字节数组作为输入参数,并在data[offset]到data[offset+length]之间的二进制数据必须符合JavaClass文件格式——它表示一个新的可用类型。

而name参数是个字符串,它指出该类型的全限定名。

当使用第一个defineClass()时,该类型将被赋以默认的保护域。

第二个defineClass时,该类型的保护域将由它的protectionDomain参数指定。

每个JVM实现都必须保证ClassLoader类的defineClass()方法能够把新类型导入到方法区中。

findSystemClass()方法接受一个字符串为参数,它指出将被装入类型的全限定名。

在版本1.0和1.1中该方法会通过启动类装载器来装载指定类型。

如果启动类装载器完成,它返回对Class对象的引用。

如果没找到相应的class文件,它会抛出ClassNotFoundException异常。

而在1.2中,findSystemClass()方法使用系统类装载器来装载指定类型。

任何JVM实现都必须保证findSystemClass方法能够以这种方式调用启动类装载器或者系统类装载器。

resolveClass()方法接受一个Class实例的引用作为参数,它将对该Class实例表示的类型执行连接动作。

而defineClass()方法只负责装载,当defineClass()方法返回一个Class实例时,也就表示指定的class文件已经被找到并装到方法区了,但是却不一定被连接和初始化。

JVM实现必须保证ClassLoader类的resolveClass()方法能够让类装载器子系统执行连接动作。

JVM的命名空间是每个类装载器都有自己的命名空间,是用来维护着由它装载的类型。

所以一个Java程序可以多次装载具有同一个全限定名的多个类型。

这样一个类型的全限定名就不足以确定在一个JVM中的唯一性。

因此,当多个类装载器都装载了同名的类型时,为了唯一标识该类型,还要在类型名称前加上装载该类型的类装载器的标识。

方法区

JVM中,关于被装载类型的信息存储在一个逻辑上被称为方法区的内存中。

当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件——一个线性二进制数据流——然后将它传输到虚拟机中。

紧接着虚拟机提取其中的类型信息,并将这些信息存储到方法区。

静态变量同样也是存储在方法区中。

JVM内部如何存储类型信息,是由具体实现的设计者来决定的。

当虚拟机运行Java程序时,会查找使用存储在方法区的类型信息,设计者应当为类型信息的内部表示设计适当的数据结构,以量保持虚拟机小巧紧凑的同时加快程序的运行效率。

由于所有线程都共享方法区,因此它们对方法区数据的访问必须设计为线程安全的。

比如,假设同时有两个线程都企图访问一个名为Lava类,而这个类还没有被装入虚拟机,那么,这时只应该有一个线程去装载它,而另一个线程只能等待。

方法区的大小不必是固定的,虚拟机可以根据应用的需要动态调整。

同样,也不必是连续的,方法区可以在一个堆中自由分配。

另外,虚拟机也可以允许用户或者程序员指定方法区的初始大小以及最小和最大尺寸等。

方法区也可以被垃圾收集。

类型信息对每个装载的类型,虚拟机都会在方法区存储以下信息:

1.这个类型的全限定名。

2.这个类型的直接超类的全限定名

3.这个类型是类类型还是接口类型

4.这个类型的访问修饰符(publicabstract或final的某个子集)。

5.任何直接超接口的全限定名的有序列表。

在javaclass文件和虚拟机中,类型名总是以全限定名出现。

全限定名在Java源码中由在javaclass文件和虚拟机中,类型名总是以全限定名出现。

全限定名在Java源码中由类所属包的名称加一个“.”,再加上类名组成。

在class文件里,所有的“.”都被斜杠“/”代替,至于在方法区全限定名的表示,是由设计者选择决定可以用任何形式和数据结构来代表。

除上面列出的基本类型信息外,虚拟机还得为每个被装载的类型存储以下信息:

1.该类型的常量池

2.字段信息

3.方法信息

4.除了常量以外的所有类(静态)变量。

5.一个到类ClassLoader的引用。

6.一个到Class类的引用

常量池:

必须为每个装载的类型维护一个常量池,就是该类型所用常量的有序集合。

字段信息:

字段名、字段类型、字段的修饰符。

方法信息:

方法名、返回类型、参数数量和类型、方法修饰符、方法的字节码、操作数栈和该方法的栈帧的局部变量区的大小、异常表。

类(静态)变量:

指向ClassLoader类的引用:

指向Class类的引用:

对于每一个被装载的类型,虚拟机都会相应地为它创建一个java.lang.Class类的实例,而且虚拟机还必须以某种方式把这个实例和存储在方法区中的类型数据关联起来。

在java中可以得到并指向Class对象的引用,Class类中的一个静态方法可让用户得到任何已装载的类的Class实例的引用,

publicstaticClassforName(StringclassName);

可以使用forName()来得到代表任何包中任何类型的Class对象的引用,只要这个类型可以被或已经被装载到当前命名空间,如果虚拟机无法把请求的类型装载到当前命名空间,那么就会抛出ClassNotFoundException异常。

Class类使得运行程序可以访问方法中保存的信息,以下是Class中声明的方法:

publicStringgetName();

publicClassgetSuuperClass();

publicbooleanisInterface();

publicClass[]getInterfaces();

publicClassLoadergetClassLoader();

getName()返回类型的全名(包名+类名);

getSuperClass()返回类型的直接超类的Class实例,如果没有则返回null;

isInterface()判断该类型是否是接口;

getInterfaces()返回一个Class对象数组,其中每个Class对象对应一个直接超接口,超接口在数组中以类型声明超

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2