`

JVM加载class文件的原理机制

    博客分类:
  • JAVA
 
阅读更多

1.Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中 

2.java中的类大致分为三种: 
    1.系统类 
    2.扩展类 
    3.由程序员自定义的类 

3.类装载方式,有两种 
    1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中,
    2.显式装载, 通过class.forname()等方法,显式加载需要的类 
  隐式加载与显式加载的区别: 
    两者本质是一样?, 

4.类加载的动态性体现 
    一个应用程序总是由n多个类组成,Java程序启动时,并不是一次把所有的类全部加载后再 
运行,它总是先把保证程序运行的基础类一次性加载到jvm中,其它类等到jvm用到的时候再加载,这样的好处是节省了内存的开销,因为java最早就是为嵌入式系统而设计的,内存宝贵,这是一种可以理解的机制,而用到时再加载这也是java动态性的一种体现 

5.java类装载器 
    Java中的类装载器实质上也是类,功能是把类载入jvm中,值得注意的是jvm的类装载器并不是一个,而是三个,层次结构如下: 
      Bootstrap Loader  - 负责加载系统类 
            | 
          - - ExtClassLoader  - 负责加载扩展类 
                          | 
                      - - AppClassLoader  - 负责加载应用类 
        为什么要有三个类加载器,一方面是分工,各自负责各自的区块,另一方面为了实现委托模型,下面会谈到该模型 

6. 类加载器之间是如何协调工作的 
      前面说了,java中有三个类加载器,问题就来了,碰到一个类需要加载时,它们之间是如何协调工作的,即java是如何区分一个类该由哪个类加载器来完成呢。 
在这里java采用了委托模型机制,这个机制简单来讲,就是“类装载器有载入类的需求时,会先请示其Parent使用其搜索路径帮忙载入,如果Parent 找不到,那么才由自己依照自己的搜索路径搜索类”,注意喔,这句话具有递归性

Java代码  收藏代码
  1. /** 
  2.  * @author Jamson Huang 
  3.  * 
  4.  */  
  5. public class TestClass {  
  6.   
  7.     /** 
  8.      * @param args 
  9.      */  
  10.     public static void main(String[] args)  throws Exception{  
  11.         //调用class加载器  
  12.         ClassLoader cl = TestClass.class.getClassLoader();  
  13.         System.out.println(cl);  
  14.         //调用上一层Class加载器  
  15.         ClassLoader clParent = cl.getParent();  
  16.         System.out.println(clParent);  
  17.         //调用根部Class加载器  
  18.         ClassLoader clRoot = clParent.getParent();  
  19.         System.out.println(clRoot);  
  20.           
  21.     }  
  22.   
  23. }  

 

Result代码  收藏代码
  1. Run, Console中出现的log信息如下:  
  2. sun.misc.Launcher$AppClassLoader@7259da  
  3. sun.misc.Launcher$ExtClassLoader@16930e2  
  4. null  


可以看出TestClass是由AppClassLoader加载器加载的 
AppClassLoader的Parent 加载器是 ExtClassLoader 
但是ExtClassLoader的Parent为 null 是怎么回事呵,朋友们留意的话,前面有提到Bootstrap Loader是用C++语言写的,依java的观点来看,逻辑上并不存在Bootstrap Loader的类实体,所以在java程序代码里试图打印出其内容时,我们就会看到输出为null 
【注:以下内容大部分引用java深度历险】 
弄明白了上面的示例,接下来直接进入类装载的委托模型实例,写两个文件,如下: 

Java代码  收藏代码
  1. /** 
  2.  * @author Jamson Huang 
  3.  * 
  4.  */  
  5. public class Test1 {  
  6.   
  7.     /** 
  8.      * @param args 
  9.      */  
  10.     public static void main(String[] args)throws Exception {  
  11.         System.out.println(Test1.class.getClassLoader());  
  12.           
  13.         Test2 test2 = new Test2();  
  14.           
  15.         test2.print();  
  16.     }  
  17.   
  18. }  
  19. /** 
  20.  * @author Jamson Huang 
  21.  * 
  22.  */  
  23. public class Test2 {  
  24.     public void print(){  
  25.         System.out.println(Test2.class);  
  26.         System.out.println(this.getClass());  
  27.         System.out.println(Test2.class.getClassLoader());  
  28.     }  
  29. }  
Result代码  收藏代码
  1. Run,Console出现log如下:  
  2. sun.misc.Launcher$AppClassLoader@7259da  
  3. class com.java.test.Test2  
  4. class com.java.test.Test2  
  5. sun.misc.Launcher$AppClassLoader@7259da  


7. 预先加载与依需求加载 

Java 运行环境为了优化系统,提高程序的执行速度,在 JRE 运行的开始会将 Java 运行所需要的基本类采用预先加载( pre-loading )的方法全部加载要内存当中,因为这些单元在 Java 程序运行的过程当中经常要使用的,主要包括 JRE 的 rt.jar 文件里面所有的 .class 文件。 

当 java.exe 虚拟机开始运行以后,它会找到安装在机器上的 JRE 环境,然后把控制权交给 JRE , JRE 的类加载器会将 lib 目录下的 rt.jar 基础类别文件库加载进内存,这些文件是 Java 程序执行所必须的,所以系统在开始就将这些文件加载,避免以后的多次 IO 操作,从而提高程序执行效率。 

图( 2 )我们可以看到多个基础类被加载, java.lang.Object,java.io.Serializable 等等。 
相对于预先加载,我们在程序中需要使用自己定义的类的时候就要使用依需求加载方法( load-on-demand ),就是在 Java 程序需要用到的时候再加载,以减少内存的消耗,因为 Java 语言的设计初衷就是面向嵌入式领域的。 
8. 自定义类加载机制 

之前我们都是调用系统的类加载器来实现加载的,其实我们是可以自己定义类加载器的。利用 Java 提供的 java.net.URLClassLoader 类就可以实现。下面我们看一段范例: 

Java代码  收藏代码
  1. try{   
  2. URL url = new URL("file:/d:/test/lib/");   
  3. URLClassLoader urlCL = new URLClassLoader(new URL[]{url});   
  4. Class c = urlCL.loadClass("TestClassA");   
  5. TestClassA object = (TestClassA)c.newInstance();   
  6. object.method();   
  7. }catch(Exception e){   
  8. e.printStackTrace();   
  9. }   



我们通过自定义的类加载器实现了 TestClassA 类的加载并调用 method ()方法。分析一下这个程序:首先定义 URL 指定类加载器从何处加载类, URL 可以指向网际网络上的任何位置,也可以指向我们计算机里的文件系统 ( 包含 JAR 文件 ) 。上述范例当中我们从 file:/d:/test/lib/ 处寻找类;然后定义 URLClassLoader 来加载所需的类,最后即可使用该实例了。 

9. 类加载器的阶层体系 

讨论了这么多以后,接下来我们仔细研究一下 Java 的类加载器的工作原理: 

当执行 java ***.class 的时候, java.exe 会帮助我们找到 JRE ,接着找到位于 JRE 内部的 jvm.dll ,这才是真正的 Java 虚拟机器 , 最后加载动态库,激活 Java 虚拟机器。虚拟机器激活以后,会先做一些初始化的动作,比如说读取系统参数等。一旦初始化动作完成之后,就会产生第一个类加载器―― Bootstrap Loader , Bootstrap Loader 是由 C++ 所撰写而成,这个 Bootstrap Loader 所做的初始工作中,除了一些基本的初始化动作之外,最重要的就是加载 Launcher.java 之中的 ExtClassLoader ,并设定其 Parent 为 null ,代表其父加载器为 BootstrapLoader 。然后 Bootstrap Loader 再要求加载 Launcher.java 之中的 AppClassLoader ,并设定其 Parent 为之前产生的 ExtClassLoader 实体。这两个加载器都是以静态类的形式存在的。这里要请大家注意的是, Launcher$ExtClassLoader.class 与 Launcher$AppClassLoader.class 都是由 Bootstrap Loader 所加载,所以 Parent 和由哪个类加载器加载没有关系。 

下面的图形可以表示三者之间的关系: 
BootstrapLoader <---(Extends)----AppClassLoader <---(Extends)----ExtClassLoader 

这三个加载器就构成我们的 Java 类加载体系。他们分别从以下的路径寻找程序所需要的类: 

BootstrapLoader : sun.boot.class.path 
ExtClassLoader: java.ext.dirs 
AppClassLoader: java.class.path 

这三个系统参量可以通过 System.getProperty() 函数得到具体对应的路径。大家可以自己编程实现查看具体的路径。

分享到:
评论

相关推荐

    codeegginterviewgroup#CodeEggDailyInterview#84.JVM加载class文件的原理机制

    JVM加载class文件的原理机制JVM加载class文件的原理机制 JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加

    JVM加载class文件的原理机制.pdf

    JVM加载class文件的原理机制.pdf

    JVM执行子系统原理

    详细介绍了JVM执行子系统的工作原理,包括类文件结构与字节码指令(Class类文件结构、JVM字节码指令简介)、JVM类加载机制(类加载器、类加载时机、类加载过程)、字节码执行引擎(运行时候的栈结构、方法调用、方法...

    JVM性能优化相关面试题21道.pdf

    JVM 面试题:Java 类加载过程、JVM 加载 Class 文件的原理机制、Java内存分配

    JVM中编译Class、内存回收、多线程原理和使用

    JVM负责装载class文件并执行,因此,首先是JDK如何将Java代码编译为class文件、如何装载class文件及如何执行class,将源码编译为class文件的实现取决于各个JVM实现或各种源码编译器。class文件通常由类加载器...

    面试必问之jvm与性能优化

    1. 描述一下 JVM 加载 Class 文件的原理机制? 在面试java工程师的时候,这道题经常被问到,故需特别注意。 Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class...

    大厂真题之携程-Java高级

    描述一下 JVM 加载 Class 文件的原理机制? 在面试 java 工程师的时候,这道题经常被问到,故需特别注意。 Java 中的所有类,都需要由类加载器装载到 JVM 中才能运行。类加 载器本身也是一个类,而它的工作就是把 ...

    java基础测试.doc

    描述一下JVM加载class文件的原理机制?  每一个class文件都是一个封装的整体,可供程序员的工程通过环境变量,包的应用调用,主要分三步:装载,链接,校验; .................

    Java面试宝典

    Java面试宝典 经典题库 Java中的异常处理机制的简单原理和应用 运行时异常与一般异常有何异同? Error与Exception有什么区别? JVM加载class文件的原理机制? …………

    深入理解JVM内存结构及运行原理全套视频加资料.txt

    包括JVM执行过程、虚拟机类加载机制、运行时数据区、GC、类加载器、内存分配与回收策略等,全套视频加资料高清无密码  第1讲 说在前面的话 免费 00:05:07  第2讲 整个部分要讲的内容说明 免费 00:06:58  第3讲...

    JVM面试专题

    7、描述一下JVM加载class文件的原理机制? 8、Java对象创建过程 9、类的生命周期【加载过程】 10、Java 中会存在内存泄漏吗,请简单描述。 11、GC是什么?为什么要有GC? 12、做GC时,⼀个对象在内存各个Space中被...

    Java进阶教程解密JVM视频教程

    * 在字节码与类加载技术章节,会从一个 class 文件开始分析其每一字节的含义。学习字节码指令的的运行流程,字节码指令与常量池、方法区的关系。掌握条件分支、循环控制、异常处理、构造方法在字节码级别的实现原理...

    深入理解Java虚拟机视频教程(jvm性能调优+内存模型+虚拟机原理)视频教程

    第86节类加载机制概述00:07:26分钟 | 第87节类加载时机00:13:15分钟 | 第88节类加载的过程-加载00:15:15分钟 | 第89节类加载的过程-验证00:10:24分钟 | 第90节类加载的过程-准备00:05:40分钟 | 第91节类加载的...

    java反射机制原理详解.docx

    我们创建一个类,通过编译,生成对应的.calss文件,之后使用java.exe加载(jvm的类加载器)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在缓存区,那么这个运行时类的本身就是一个class的实例 ...

    java笔试题

    21、描述一下JVM加载class文件的原理机制? 22、char 型变量中能不能存贮一个中文汉字,为什么? 23、抽象类(abstract class)和接口(interface)有什么异同? 24、静态嵌套类(Static Nested Class)和内部类...

    Java基础加强之类加载器

    类加载是指将类的class文件读入内存,并为之创建一个Java.lang.Class对象,也是说当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。  类加载器负责加载所有类,系统为所有被载入内存中的类生成一...

    Java编程经验

    2. 关于寻找class文件原理?? 建议大家在入门的时候在命令行窗口编译和运行,不要借助JCreator或者Eclipse等IDE去帮助做那些事情。尝试自己这样做: javac -classpath yourpath *.java java -classpath yourpath ...

    涵盖了90%以上的面试题

    JVM加载class文件的原理 双亲委派模型 为什么要自定义类加载器 如何自定义类加载器 什么是GC 内存泄漏和内存溢出 Java的内存模型(JVM的内存划分) JVM内存模型1.7和1.8的区别 如何判断一个对象是否是垃圾对象 垃圾...

    千方百计笔试题大全

    27、描述一下JVM 加载class 文件的原理机制? 10 28、char 型变量中能不能存贮一个中文汉字?为什么? 10 29、abstract class 和interface 有什么区别? 10 30、Static Nested Class 和Inner Class 的不同? 11 31、java...

Global site tag (gtag.js) - Google Analytics