JVM加载过程及异常
1、虚拟机执行过程
虚拟机(jvm)把描述类的数据从class文件或其他形式数据加载到内存,并对数据进行校验、准备、解析和初始化。最终形成可以被虚拟机直接使用的Java 类型。这就是虚拟机的类加载机制。
类加载的生命周期包括:加载、链接(验证、准备和解析)、初始化、使用、卸载。
启 动
Jvm通过调用某个类指定类的main方法启动,传递给main所在类一个字符串数组。如下:
java Test hello smurfs, welcome to jvm.这样jvm通过加载Test.class文件,然后把hello smurfs, welcome to jvm.作为5个长度的字符串数据传递给Test类的main方法去执行。
Jvm加载Test.class文件后,通过链接步骤,把Test.class生成的class对象链接到对应的类型,然后进行初始化操作,在所有都正确完成之后,才构造了一个完整的Test类对象,进而才能正确的执行方法。
⑴class文件装载:寻找一个具有特定名称的类的二进制形式,并且用这个二进制形式构造一个代表该类的class对象的过程叫装载(是个动词,指过程)。装载是通过ClassLoader和其子类实现的,ClassLoader的不同子类可以实现不同的装载策略,包括class文件加密()、特殊位置加载(网络加载)等都是通过classloader来完成的。类加载后的信息存在于jvm的方法区域内,这个区域缓存这类的信息,并且这个区域基本是不进行垃圾回收的,因此如果没有进行classloader加载对象的清空,新的class文件替代旧class文件后,类信息并没有被替换。
在加载阶段,虚拟机需要完成以下3件事情:
1、通过类的全限定名来获取定义此类的二进制流;
2、将这个二进制流所代表的静态存储结构转化为方法区(jvm内存)的运行时数据
3、在Java 堆(jvm内存)中生成一个代表类的java.lang.Class对象,作为方法区这些数据的入口。
如果类的装载出现错误,会抛出LinkageError异常的以下3个子类示例:
lClassCircularityError:因一个类或接口是自身的超类而不能被加载。
lClassFormatError:所要求的编译后的类的二进制数据是损坏的。
lNoClassDefFoundError:找不到类的定义。
以上3中error,以下一一举例:
l在不包含Test.java的目录里执行java Test后出现NoClassDefFoundError
l接下来看看ClassFormatError错误,首先编写个Test.java文件,内容如下:
修改编译后Test.class文件,把其中的println改成printl后,再通过java Test执行:
l最后来看ClassCircularityError错误。正常清空下,这种错误是不会存在的,但是当大型项目,需要很多人提交代码时就可能会出现问题。
首先编写2个类,Test和A,Test继承与A,详细代码如下:
编译后产生Test.class和A.class 2个2进制文件,删除A.class,把Test.class改名保护起来为Test.class.a,再编写Test和A,这次A继承自Test,详细代码如下:
这次编译后删除Test.class,保留A.class文件,然后把先前改名的Test.class.a该回Test.class,再执行java Test后