`
yinter
  • 浏览: 240309 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java虚拟机类装载--原理、实现和应用

    博客分类:
  • java
阅读更多
一、引言

  Java虚拟机(JVM)的类装载就是指将包含在类文件中的字节码装载到JVM中, 并使其成为JVM一部分的过程。JVM的类动态装载技术能够在运行时刻动态地加载或替换系统的某些功能模块, 而不影响系统其他功能模块的正常运行。本文将分析JVM中的类装载系统,探讨JVM中类装载的原理、实现及应用。

  二、Java虚拟机的类装载实现和应用

  2.1 装载过程简介

  所谓装载就是寻找一个类或是个接口的二进制形式并用该二进制形式来构造代表这个类或是这个接口的class对象的过程,其中类或接口的名称是给定了的。当然名称也能通过计算得到,不过更常见的是通过搜索原始码经过编译器编译后所得到的二进制形式来构造。

  在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又能分成校验、准备和解析三步,除了解析外,其他步骤是严格按照顺序完成的,各个步骤的主要工作如下:

  装载:查找和导入类或接口的二进制数据;

  链接:执行下面的校验、准备和解析步骤,其中解析步骤是能选择的;

  校验:检查导入类或接口的二进制数据的正确性;

  准备:给类的静态变量分配并初始化存储空间;

  解析:将符号引用转成直接引用;

  初始化:激活类的静态变量的初始化Java代码和静态Java代码块。

  至于在类装载和虚拟机启动的过程中的具体细节和可能会抛出的错误,请参看《Java虚拟机规范》及《深入Java虚拟机》,他们在网络上面的资源地址是:

  http://java.sun.com/docs/books/vmspec/2nd-edition/html/Preface.doc.html

  http://www.artima.com/insidejvm/ed2/index.html

  由于本文的讨论重点不在此就不再多叙述。

  2.2 装载的实现

  JVM中类的装载是由ClassLoader和他的子类来实现的,Java ClassLoader 是个重要的Java运行时系统组件。他负责在运行时查找和装入类文件的类。

  在Java中,ClassLoader是个抽象类,他在包java.lang中,能这样说,只要了解了在ClassLoader中的一些重要的方法,再结合上面所介绍的JVM中类装载的具体的过程,对动态装载类这项技术就有了一个比较大概的掌控,这些重要的方法包括以下几个:

  ①loadCass方法 loadClass(String name ,boolean resolve)其中name参数指定了JVM需要的类的名称,该名称以包表示法表示,如Java.lang.Object;resolve参数告诉方法是否需要解析类,在初始化类之前,应考虑类解析,并不是所有的类都需要解析,如果JVM只需要知道该类是否存在或找出该类的超类,那么就不必解析。这个方法是ClassLoader 的入口点。

  ②defineClass方法 这个方法接受类文件的字节数组并把他转换成Class对象。字节数组能是从本地文件系统或网络装入的数据。他把字节码分析成运行时数据结构、校验有效性等等。

③findSystemClass方法 findSystemClass方法从本地文件系统装入文件。他在本地文件系统中寻找类文件,如果存在,就使用defineClass将字节数组转换成 Class对象,以将该文件转换成类。当运行Java应用程式时,这是JVM 正常装入类的缺省机制。

  ④resolveClass方法 resolveClass(Class c)方法解析装入的类,如果该类已被解析过那么将不做处理。当调用loadClass方法时,通过他的resolve 参数决定是否要进行解析。

  ⑤findLoadedClass方法 当调用loadClass方法装入类时,调用findLoadedClass 方法来查看ClassLoader是否已装入这个类,如果已装入,那么返回Class对象,否则返回NULL。如果强行装载已存在的类,将会抛出链接错误。

  2.3 装载的应用

  一般来说,我们使用虚拟机的类装载时需要继承抽象类java.lang.ClassLoader,其中必须实现的方法是 loadClass(),对于这个方法需要实现如下操作:(1) 确认类的名称;(2) 检查请求要装载的类是否已被装载;(3) 检查请求加载的类是否是系统类;(4) 尝试从类装载器的存储区获取所请求的类;(5) 在虚拟机中定义所请求的类;(6) 解析所请求的类;(7) 返回所请求的类。

  所有的Java 虚拟机都包括一个内置的类装载器,这个内置的类库装载器被称为根装载器(bootstrap ClassLoader)。根装载器的特别之处是他只能够装载在设计时刻已知的类,因此虚拟机假定由根装载器所装载的类都是安全的、可信任的,能不经过安全认证而直接运行。当应用程式需要加载并不是设计时就知道的类时,必须使用用户自定义的装载器(user-defined ClassLoader)。下面我们举例说明他的应用。 
 
public abstract class MultiClassLoader extends ClassLoader{
  ...
  public synchronized Class loadClass(String s, boolean flag)
  throws ClassNotFoundException
  {
  /* 检查类s是否已在本地内存*/
  Class class1 = (Class)classes.get(s);
  /* 类s已在本地内存*/
  if(class1 != null) return class1;
  try/*用默认的ClassLoader 装入类*/ {
  class1 = super.findSystemClass(s);
  return class1;
  }
  catch(ClassNotFoundException _ex) {
  System.out.println(">> Not a system class.");
  }
  /* 取得类s的字节数组*/
  byte abyte0[] = loadClassBytes(s);
  if(abyte0 == null) throw new ClassNotFoundException();
  /* 将类字节数组转换为类*/
  class1 = defineClass(null, abyte0, 0, abyte0.length);
  if(class1 == null) throw new ClassFormatError();
  if(flag) resolveClass(class1); /*解析类*/
  /* 将新加载的类放入本地内存*/
  classes.put(s, class1);
  System.out.println(">> Returning newly loaded class.");
  /* 返回已装载、解析的类*/
  return class1;
  }
  ...
  }

  三、Java虚拟机的类装载原理

  前面我们已知道,一个Java应用程式使用两种类型的类装载器:根装载器(bootstrap)和用户定义的装载器(user- defined)。根装载器是Java虚拟机实现的一部分,举个例子来说,如果一个Java虚拟机是在目前已存在并且正在被使用的操作系统的顶部用C程式来实现的,那么根装载器将是那些C程式的一部分。根装载器以某种默认的方式将类装入,包括那些Java API的类。在运行期间一个Java程式能安装用户自己定义的类装载器。根装载器是虚拟机固有的一部分,而用户定义的类装载器则不是,他是用Java语言写的,被编译成class文件之后然后再被装入到虚拟机,并像其他的所有对象相同能被实例化。 Java类装载器的体系结构如下所示:

Java的类装载模型是一种代理(delegation)模型。当JVM 需求类装载器CL(ClassLoader)装载一个类时,CL首先将这个类装载请求转发给他的父装载器。只有当父装载器没有装载并无法装载这个类时,CL才获得装载这个类的机会。这样, 所有类装载器的代理关系构成了一种树状的关系。树的根是类的根装载器(bootstrap ClassLoader) , 在JVM 中他以"null"表示。除根装载器以外的类装载器有且仅有一个父装载器。在创建一个装载器时, 如果没有显式地给出父装载器, 那么JVM将默认系统装载器为其父装载器。Java的基本类装载器代理结构如图2所示:

  下面针对各种类装载器分别进行周详的说明。

  根(Bootstrap) 装载器:该装载器没有父装载器,他是JVM实现的一部分,从sun.boot.class.path装载运行时库的核心代码。

  扩展(Extension) 装载器:继承的父装载器为根装载器,不像根装载器可能和运行时的操作系统有关,这个类装载器是用纯Java代码实现的,他从java.ext.dirs (扩展目录)中装载代码。

  系统(System or Application) 装载器:装载器为扩展装载器,我们都知道在安装JDK的时候要设置环境变量(CLASSPATH ),这个类装载器就是从java.class.path(CLASSPATH 环境变量)中装载代码的,他也是用纯Java代码实现的,同时还是用户自定义类装载器的缺省父装载器。

  小应用程式(Applet) 装载器: 装载器为系统装载器,他从用户指定的网络上的特定目录装载小应用程式代码。

  在设计一个类装载器的时候,应该满足以下两个条件:

  对于相同的类名,类装载器所返回的对象应该是同一个类对象

  如果类装载器CL1将装载类C的请求转给类装载器CL2,那么对于以下的类或接口,CL1和CL2应该返回同一个类对象:a)S为C的直接超类;b)S为C的直接超接口;c)S为C的成员变量的类型;d)S为C的成员方法或构建器的参数类型;e)S为C的成员方法的返回类型。

  每个已装载到JVM中的类都隐式含有装载他的类装载器的信息。类方法getClassLoader 能得到装载这个类的类装载器。一个类装载器认识的类包括他的父装载器认识的类和他自己装载的类,可见类装载器认识的类是他自己装载的类的超集。注意我们能得到类装载器的有关的信息,不过已装载到JVM中的类是不能更改他的类装载器的。

  Java中的类的装载过程也就是代理装载的过程。比如:Web浏览器中的JVM需要装载一个小应用程式TestApplet。JVM调用小应用程式装载器ACL(Applet ClassLoader)来完成装载。ACL首先请求他的父装载器, 即系统装载器装载TestApplet是否装载了这个类, 由于TestApplet不在系统装载器的装载路径中, 所以系统装载器没有找到这个类, 也就没有装载成功。接着ACL自己装载TestApplet。ACL通过网络成功地找到了TestApplet.class 文件并将他导入到了JVM中。在装载过程中, JVM发现TestAppet是从超类java.applet.Applet继承的。所以JVM再次调用ACL来装载 java.applet.Applet类。ACL又再次按上面的顺序装载Applet类, 结果ACL发现他的父装载器已装载了这个类, 所以ACL就直接将这个已装载的类返回给了JVM , 完成了Applet类的装载。接下来,Applet类的超类也相同处理。最后, TestApplet及所有有关的类都装载到了JVM中。

  四、结论

  类的动态装载机制是JVM的一项核心技术, 也是容易被忽视而引起非常多误解的地方。本文介绍了JVM中类装载的原理、实现及应用,尤其分析了ClassLoader的结构、用途及怎么利用自定义的 ClassLoader装载并执行Java类,希望能使读者对JVM中的类装载有一个比较深入的理解
分享到:
评论

相关推荐

    Java虚拟机类装载:原理、实现与应用.doc

    Java虚拟机类装载:原理、实现与应用.doc

    Java虚拟机类装载机制

    简单的介绍和描述Java虚拟机类装载:原理、实现与应用

    Java虚拟机类装载:原理、实现与应用

    类的动态装载机制是JVM的一...本文介绍了JVM中类装载的原理、实现以及应用,尤其分析了ClassLoader的结构、用途以及如何利用自定义 的ClassLoader装载并执行Java类,希望能使读者对JVM中的类装载有一个比较深入的理解。

    JAVA虚拟机的类装载机制的原理分析与应用研究.pdf

    详细描述java虚拟机内部加载类机制和原理

    深入Java虚拟机

    现在很多JAVA程序员,都只是知道用JAVA,而不知道它的原理实现,深入Java虚拟机,有助于了解Java虚拟机类装载:原理、实现与应用

    YJVM—一种运行在嵌入式Linux内核中的Java虚拟机的设计与实现

    本文从对嵌入式操作系统的讨论入手,结合Java虚拟机的原理和研究状况阐述了YJVM的设计和实现要点,体现了YJVM相比现有的嵌入式Java解决方案和Java操作系统的优势。本文的主要研究内容及成果包括: 1、作为一种...

    深入研究Java 的类加载机制

    Java 类的动态装载机制是Java 虚拟机的一项核心技术,可以在运行时刻...介绍了Java 虚拟机中类的动态装载机制的原理、实现 及应用,分析了类装载器的结构、用途,阐述了利用自定义类装载器装载并执行Java 类的过程。

    JAVA上百实例源码以及开源项目

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

    JAVA上百实例源码以及开源项目源代码

     Java绘制图片火焰效果,源代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标...

    深入JVM内核 - 原理、诊断与优化

    详细介绍ClassLoader的原理和应用。分析2个案例,说明ClassLoader的使用。 第七课 性能监控工具 线程死锁分析 OOM分析 介绍常用的JVM诊断和分析工具,并以死锁和OOM为例,展示这些工具的使用。 第八课 分析Java...

    java 面试题 总结

    接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它...

    疯狂JAVA讲义

    第1章 Java概述 1 1.1 Java语言的发展简史 2 1.2 Java的竞争对手及各自优势 4 ...11.8.1 Image抽象类和BufferedImage实现类 425 11.8.2 使用ImageIO输入/输出位图 427 11.9 剪贴板 432 11.9.1 数据传递的类...

    超级有影响力霸气的Java面试题大全文档

    接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它...

    java核心面试技术点

    JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。 1说说JVM原理?内存泄露与溢出区别,何时产生内存泄露? 编译源代码为...

    java核心面试

    JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。 1说说JVM原理?内存泄露与溢出区别,何时产生内存泄露? 编译源代码为...

Global site tag (gtag.js) - Google Analytics