`

一步一步深入jvm(2)—jvm类装载:原理、实现与应用(转)

    博客分类:
  • jvm
阅读更多

一、引言

      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类装载器的体系结构如下所示:

图1  Java的类装载的体系结构

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

图2  Java类装载的代理结构

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

      根(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中的类装载有一个比较深入的理解。

  • 大小: 9 KB
  • 大小: 4.8 KB
分享到:
评论

相关推荐

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

    总的来说,Java虚拟机的类装载原理、实现和应用是一个深奥且重要的主题,涉及到Java运行时环境的多个核心层面,对于理解和调试Java程序,以及设计高效、灵活的系统架构都有着至关重要的作用。开发者需要深入理解这个...

    揭秘Java虚拟机-JVM设计原理与实现

    《揭秘Java虚拟机-JVM设计原理与实现》这本书深入探讨了Java虚拟机(JVM)的工作原理及其在Java编程中的核心地位。Java虚拟机是Java平台的核心组成部分,它负责执行字节码,为开发者提供了跨平台的运行环境。以下是...

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

    1. **JVM结构与原理**:首先,我们需了解JVM的基本架构,包括类装载器、运行时数据区、执行引擎、本地方法接口和本地库。特别是堆内存、栈内存、方法区(元空间)以及垃圾收集机制,它们是理解JVM运行时行为的关键。...

    jvm类装载器原理

    《JVM类装载器原理详解》 Java的JVM(Java Virtual Machine)类装载器是...总之,深入理解JVM的类装载器原理,不仅有助于我们更好地理解和调试Java程序,也有助于我们在实际开发中实现更加高效和灵活的类管理机制。

    深入JVM内核—原理、诊断与优化视频教程-6. 类装载器

    本教程聚焦于深入理解JVM内核,特别是类装载器的原理、诊断与优化。在这个第六部分中,我们将探讨以下几个核心知识点: 1. **类装载器的层次结构**:Java的类装载器采用双亲委派模型,即当一个类装载器接到加载类的...

    深入jvm 内核-原理,诊断于优化视频教程

    ### 深入JVM内核:原理、诊断与优化 #### 一、JVM基础知识 **1.1 JVM概念** Java虚拟机(Java Virtual Machine,简称JVM)是一种用于执行Java字节码的虚拟机。它为Java程序提供了一个运行环境,能够独立于硬件平台...

    Java虚拟机类装载的原理及实现

    本文将详细探讨JVM中的类装载系统,解析类装载的原理、实现方式及其应用场景。 #### 类装载概述 类装载是指将类文件中的字节码加载到JVM中,使其成为JVM运行环境的一部分。这一过程不仅限于程序启动时,也可以在...

    JAVA应用JVM原理及参数调优深入讲解视频.rar

    本课程深入讲解了JVM的工作原理以及如何进行参数调优,旨在帮助开发者提升应用程序的性能和稳定性。 首先,我们来探讨JVM的基本原理。JVM是一个抽象的计算机,它具有硬件系统的许多特性,如内存管理、指令集等。当...

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

    介绍JVM中对多线程锁的实现。 第十课 class文件结构 ASM库介绍 介绍JVM规范中的最重要的内容——Class文件结构,同时介绍ASM库的使用以及对class文件的修改。 第十一课 字节码执行 案例以及javap JIT及相关参数 ...

    深入理解JVM.

    深入理解JVM,首先要明白Java技术的组成部分,包括Java编程语言、Java类文件格式、Java虚拟机(JVM)和Java应用程序接口(Java API)。这些组件共同构成了Java平台,使得Java程序能够实现跨平台运行。 Java虚拟机是...

    深入JVM概要 JVM详解

    本文将详细介绍Java虚拟机(JVM)的内部机理和实现原理,从类型的生命周期、方法区、常量池、类加载器、垃圾收集器、栈和局部变量等方面对JVM进行深入解析。 类型的生命周期 类型的生命周期是JVM中最重要的部分,...

    java-jvm虚拟机原理.ppt

    Java虚拟机(JVM)是Java程序运行的核心组件,它为Java代码提供了平台无关的运行环境。本篇文章将深入探讨JVM的生命周期、体系...理解JVM的工作原理对于优化Java应用性能、调试问题和设计高效的内存管理策略至关重要。

    java虚拟机深入JVM内核—原理、诊断与优化视频教程网盘下载

    一、JVM结构与原理 1. 类装载子系统:负责加载、验证、解析和初始化类文件。 2. 运行时数据区:包括堆、方法区、虚拟机栈、本地方法栈和程序计数器。每个线程都有自己独立的虚拟机栈和本地方法栈,而堆和方法区则是...

    Java虚拟机JVM性能优化(一):JVM知识总结

    在Java应用的性能优化中,深入理解JVM的工作原理和进行适当的调优至关重要。本篇文章将对JVM的基础知识进行总结,并探讨如何通过调整JVM参数来提升性能。 首先,我们需要了解JVM的主要组成部分:类装载器、运行时...

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

    本文将深入探讨Java虚拟机的类装载机制,包括其原理、工作流程以及在实际开发中的应用。 类装载机制是Java虚拟机在运行时动态加载和初始化类的过程。这一过程涉及到了四个主要角色:类装载器(ClassLoader)、类的...

    java之jvm学习笔记五(实践写自己的类装载器)

    在深入理解JVM的过程中,编写自己的类装载器(ClassLoader)是一个非常实用且有趣的实践。这个“java之jvm学习笔记五(实践写自己的类装载器)”很可能是对这一主题的详细探讨。 类装载器在Java中的主要职责是动态...

    [转载]深入理解JVM

    1. **类装载**:当程序首次引用某个类时,JVM会通过类装载子系统加载该类的字节码文件。 2. **验证**:JVM会检查字节码文件是否符合JVM规范的要求,确保程序的正确性和安全性。 3. **准备**:为类的静态变量分配内存...

    Java深度历险(2)--深入类装载器

    ### Java深度历险(2)--深入类装载器 #### 前言 在现代软件开发领域,特别是使用Java这样的高级编程语言时,“动态性”是一个非常重要的概念。它指的是程序能够在运行时根据需要加载、卸载或替换部分代码的能力。这...

Global site tag (gtag.js) - Google Analytics