Java虚拟机加载器

来源:互联网 发布:洛克人网络争霸战粤语 编辑:程序博客网 时间:2024/06/06 02:49

在java中,main()方法是java应用程序的入口方法。java虚拟机通过main方法找到需要启动的运行程序,并且检查main函数所在类是否被java虚拟机装载。如果没有装载,那么就装载该类,并且装载所有相关的其他类。因此程序在运行的时候,第一个执行的方法就是main()方法。通常情况下, 如果要运行一个类的方法,必须首先实例化出来这个类的一个对象,然后通过"对象名.方法名()"的方式来运行方法,但是因为main是程序的入口,这时候还没有实例化对象,因此将main方法声明为static的,这样这个方法就可以直接通过“类名.方法名()”的方式来调用。


编译后在命令行模式下键入: java HelloApp run virtual machine

  将通过调用HelloApp的方法main来启动java虚拟机,传递给main一个包含三个字符串"run"、"virtual"、"machine"的数组。现在我们略述虚拟机在执行HelloApp时可能采取的步骤。

  开始试图执行类HelloApp的main方法,发现该类并没有被装载,也就是说虚拟机当前不包含该类的二进制代表,于是虚拟机使用ClassLoader试图寻找这样的二进制代表。如果这个进程失败,则抛出一个异常。类被装载后同时在main方法被调用之前,必须对类HelloApp与其它类型进行链接然后初始化。链接包含三个阶段:检验,准备和解析。检验检查被装载的主类的符号和语义,准备则创建类或接口的静态域以及把这些域初始化为标准的默认值,解析负责检查主类对其它类或接口的符号引用,在这一步它是可选的。类的初始化是对类中声明的静态初始化函数和静态域的初始化构造方法的执行。一个类在初始化之前它的父类必须被初始化。整个过程如下:


当JVM加载一个类的时候,下层的加载器会将将任务委托给上一层类加载器,上一层加载检查它的命名空间中是否已经加载这个类,如果已经加载,直接使用这个类。如果没有加载,继续往上委托直到顶部。检查完了之后,按照相反的顺序进行加载,如果Bootstrap加载器找不到这个类,则往下委托,直到找到类文件。对于某个特定的类加载器来说,一个Java类只能被载入一次,也就是说在Java虚拟机中,类的完整标识是(classLoader,package,className)。一个雷可以被不同的类加载器加载。


举个具体的例子来说明,现在加入我有一个自己定义的类MyClass需要加载,如果不指定的话,一般交App(System)加载。接到任务后,System检查自己的库里是否已经有这个类,发现没有之后委托给Extension,Extension进行同样的检查,发现还是没有继续往上委托,最顶层的Boots发现自己库里也没有,于是根据它的路径(Java 核心类库,如java.lang)尝试去加载,没找到这个MaClass类,于是只好(人家看好你,交给你完成,你无能为力,只好交给别人啦)往下委托给Extension,Extension到自己的路径(JAVA_HOME/jre/lib/ext)是找,还是没找到,继续往下,此时System加载器到classpath路径寻找,找到了,于是加载到Java虚拟机。

现在假设我们将这个类放到JAVA_HOME/jre/lib/ext这个路径中去(相当于交给Extension加载器加载),按照同样的规则,最后由Extension加载器加载MyClass类,看到了吧,统一各类被两次加载到JVM,但是每次都是由不同的ClassLoader完成。


》》可见性限制

下层的加载器能够看到上层加载器中的类,反之则不行,也就是是说委托只能从下到上。


》》不允许卸载类

类加载器可以加载一个类,但是它不能卸载一个类。但是类加载器可以被删除或者被创建。


当类加载完毕之后,JVM继续按照下图完成其他工作:


框图中各个步骤简单介绍如下:

Loading:文章前面介绍的类加载,将文件系统中的Class文件载入到JVM内存(运行数据区域)

Verifying:检查载入的类文件是否符合Java规范和虚拟机规范。

Preparing:为这个类分配所需要的内存,确定这个类的属性、方法等所需的数据结构。(Prepare a data structure that assigns the memory required by classes and indicates the fields, methods, and interfaces defined in the class.)

Resolving:将该类常量池中的符号引用都改变为直接引用。(不是很理解)

Initialing:初始化类的局部变量,为静态域赋值,同时执行静态初始化块。



0 0