JVM中的class文件校验器,用于保证装在的class文件内容正确,以及它们之间协调一致。它主要负责确保程序执行的安全性,遇见非正常的class文件时,它会提示异常,并阻止JVM运行这些可疑文件。
class文件由字节码组成,一般由Java编译器生成,当然其他的一些字节码组成的文件也能充当class文件,这就要看它的具体内容。如果这个class文件由某个带有bug的编辑器生成,或者是被人恶意篡改了一些内容,比如在一个方法里悄悄加上跳转到方法之外指令,那么在执行这个class文件时,JVM将崩溃。文件校验器正是要保证class文件的内容、结构、完整性都符合JVM执行的要求。因此,它会在字节码执行之前进行class文件扫描,扫描分为四次:
1,class文件结构检查
此次扫描目的是确定class文件符合Java class的基本结构,比如文件是否以0XCAFEBABE这四个字节开头,文件是否包含正确的版本号和此版本号。我们在运行一些程序时偶尔会遇见java.lang.UnsupportedClassVersionError
错误,然后后面跟着一个版本号错误的提示信息,这就是class文件结构检查时抛出的错误,表明class文件是由另一个版本的Java编译器生成的,而这个版本的编译器不在当前的JVM支持范围以内。另外,这次扫描还会检查文件的完整性(头尾完整),以及文件中对数据结构长度信息的描述是否与文件内容总长度符合,以确保文件正确的定义了一个新的class类。
2,类型数据的语义检查
第二次扫描针对文件的各个组成部分,比如类的方法和属性。方法的返回类型、参数都会存储为一个字符串,这个字符串必须满足的Java规则,校验器将会校验所有的方法描述符(返回类型、参数、参数个数等),确定它们符合Java语法。另外,它还会对类本身应该遵循的规则进行校验,必须是否是Object或由Object类继承而来,是否继承了final类型的类,是否重写了final类型的方法,常量的定义是否正确。尽管编译器已经进行语法的检验,但是JVM还是需要再次进行校验,确定这些class文件是由可靠的编译器生成的。如果某位程序员恶意修改了编译器,使得它可以编译一些语法错误的Java文件,那么在这里将校验失败,并抛出一个错误。
3,字节码验证
class文件中,方法是由字节码流来表示的,这次扫描中JVM将对对字节码流进行分析。字节码流是由一些成为操作码组成的序列,而操作码后面则跟着一个或多个操作数。操作码、操作数的概念见
http://define.cnki.net/WebForms/WebDefines.aspx?searchword=%E6%93%8D%E4%BD%9C%E7%A0%81
原文关于字节码验证一段:
写道
The bytecode streams that represent Java methods are a series of one-byte instructions, called opcodes, each of which may be followed by one or more operands. The operands supply extra data needed by the Java Virtual Machine to execute the opcode instruction. The activity of executing bytecodes, one opcode after another, constitutes a thread of execution inside the Java Virtual Machine. Each thread is awarded its own Java Stack, which is made up of discrete frames. Each method invocation gets its own frame, a section of memory where it stores, among other things, local variables and intermediate results of computation. The part of the frame in which a method stores intermediate results is called the methodís operand stack. An opcode and its (optional) operands may refer to the data stored on the operand stack or in the local variables of the methodís frame. Thus, the virtual machine may use data on the operand stack, in the local variables, or both, in addition to any data stored as operands following an opcode when it executes the opcode.
大致意思是:class文件中Java的方法是字节码流代替的,字节码流就是流操作码序列,而操作码就是单字节指令,JVM中定义了220条这样的指令。操作码后面会紧随一个或多个操作数,操作码决定要完成的操作,操作数指参加运算的数据及其所在的单元地址。JVM会创建线程来执行字节码流,其实就是一个接一个执行字节码流中的操作码。每个线程都会分配一个栈,栈由许多帧组成。每次方法调用都将产生一个新的帧,帧就是一块内存区域,用来存储中间结果和局部变量。帧里面用来存储中间结果的部分称为操作数栈,操作码和操作数可能会用到操作数栈中的数据或者帧中的局部变量。这样,在执行操作码是时,JVM不但可以使用紧随在其后的操作数,还可以使用操作数栈中的数据,以及局部时变量。
校验器在这趟扫描里要做大量的工作,在执行字节码流中的一个特定操作码时,它保证无论如何执行,总能在操作数栈中得到一致的数据。校验器将确保局部变量在使用之前已经赋值,类的成员变量的赋值正确,类的成员方法的调用符合参数要求。校验器还必须保证,操作码、操作数以及在执行中将产生的操作数栈中的数据正确。字节码校验还有其他校验工作要做。
完成字节码校验以后,它将确保这个class文件安全的在JVM上执行。
经过1,2,3次扫描,class文件校验器可以保证class文件在结构到内容正确,满足java规范,包含的字节码可以在JVM上安全的执行。如果扫描中出现了问题,则会抛出错误,并阻止JVM执行。
4,符号引用的校验
前三次扫描发生在class文件执行以前,而第四次则发生在动态连接时。
动态链接时,class中的引用的符号将被解析,文件校验器必须保证引用正确,JVM将开始校验被引用的class文件。因为涉及到其他的class文件,类装载器可能需要装载这个class,JVM采用延迟装载机制,一直到class被使用时才会装载。有时为了提高装载速度,会进行预先装载,尽管存在预先装载,JVM还是表现出延迟装载的特征。比如预先装载时有一个引用的class文件找不到,那么它不会立即抛出NoClassDefFoundError,而是等到这个class被使用时再抛出。这样第四次扫描可能会紧跟着前三次进行,也可可能在前三次扫描完毕以后很久再执行。
符号引用校验包括符号的引用信息的校验,引用是否合法。比如引用的方法名称、参数是否正确,类名、成员变量名是否正确等。JVM在解析引用时进行以下操作:
A,查找被引用的类,必要的话装载它
B,将符号引用替换为直接引用,比如将指向方法的引用——方法名替换为指向方法的指针或偏移量。
JVM将记住这个直接引用,以便下次遇到相同的引用时,不必再进行解析。
另外,在第四次扫描中,校验器还将检查兼容性,比如在大型的系统中,class被拆分为许多包,其中一些包的修改并不会导致所有引用它的包的重新编译,这时候在运行时就会提示一些java.lang.NoSuchMethodError,
java.lang.NoSuchFieldError错误。
分享到:
相关推荐
在Java世界中,虚拟机(JVM)是执行Java字节码的核心...而"JVM之用Java解析class文件共10页.pdf.zip"这个压缩包很可能包含了一份详细的教程或论文,深入讲解了这个主题,对于Java开发者来说,是一个值得学习的资源。
通过对JavaClass文件结构的理解,可以有效地实现一个JavaClass文件校验器,进而确保加载到JVM上的Class文件是安全可靠的。这对于Java开发者而言是一项重要的技能,有助于提高Java程序的质量和性能。
在Java编程中,类加载器(Class Loader)扮演着至关重要的角色,它负责查找并加载Java类到JVM内存中。本部分我们将深入探讨JVM中的类加载器,特别是根类加载器、扩展类加载器和系统类加载器。 首先,让我们了解类...
JVM的类加载机制是JVM的核心机制之一,它把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初识化,形成可以被虚拟机直接使用的Java类型。 Java代码执行流程是JVM的核心流程之一,它首先通过...
主要描述了JVM结构组成、对编译后的class文件格式、对class文件的校验(class文件校验器)、jvm指令、JVM中对线程和锁的处理机制、以及sun虚拟机 的具体实现的优化(使用quick伪指令),对于想了解JVM运行细节,字节...
JVM负责加载Class文件,校验字节码,以及执行字节码指令。Java虚拟机执行引擎负责执行字节码指令,它包括一个即时编译器(Just-In-Time,JIT)编译器和一个解释器。 4. **HotSpot VM**:HotSpot是JVM的一个高性能...
《JVM类装载器原理详解》 Java的JVM(Java Virtual Machine)类装载器是Java运行时系统的重要组成部分,负责在程序运行期间查找并加载类的二进制数据。理解类装载器的工作原理对于优化Java应用性能和实现动态加载类...
- **描述**:如果新的Class校验器检查失败,则使用旧的校验器。这主要是为了解决Java 6向后兼容性问题,因为Java 6最高向下兼容到Java 1.2版本,而这两个版本之间的class信息存在较大差异。 - **关联选项**:`-XX:...
- **字节码校验器**:检查字节码的正确性和安全性。 - **解释执行器**:逐行解释执行字节码。 2. **安全健壮** - Java设计了许多安全特性来确保应用程序的安全性,包括沙箱模型、类型安全等。 3. **面向对象*...
1. **类加载器(ClassLoader)**:负责将.class文件加载到内存中,并对其进行校验和解析,最终转换成运行时的数据结构。 2. **运行时数据区(Runtime Data Area)**:包括方法区、堆、程序计数器、本地方法栈以及...
在JVM中,类加载器负责将描述类的数据从`.class`文件加载到内存中,并对其进行校验、转换解析及初始化,最终形成可以直接被虚拟机使用的Java类型。类加载器主要包括以下几种: - **Bootstrap ClassLoader**(引导类...
- **功能**:如果新的Class校验器检查失败,则使用旧的校验器。 - **默认状态**:启用(针对Java 6)。 - **说明**:为了解决JDK6与早期版本的兼容性问题,当新校验器遇到无法识别的class文件时,会退回到旧校验...
- **验证**: 根据JVM规范,校验加载进来的`.class`文件是否符合规范,以防止JVM文件被篡改。 - **准备**: 给类的非`final`修饰的`static`变量分配内存空间,并进行默认初始化。 - **解析**: 将常量池内的符号引用...
1. 为什么学习JVM? - 面试需求:随着企业对技术人才的要求提高,面试中对JVM的了解变得越来越重要。 - 理解Java:JVM是Java的核心组成部分,深入理解JVM有助于理解Java的工作原理。 - 解决线上问题:通过JVM的...
1. 类加载器:负责加载.class文件,解析类信息并存储在内存中。 2. 字节码解析:将Java字节码转换为可执行的指令序列。 3. 运行时数据区:模拟Java的堆、栈、方法区等内存区域,执行指令时所需的上下文。 4. 操作数...
类加载器负责寻找和加载类文件,通常是根据类名从类路径中找到对应的.class文件。 2. 验证:验证是确保加载的类文件符合Java语言规范,防止恶意代码破坏系统的安全机制。它检查字节码的语法、数据类型、操作符以及...