`

JVM总结(2)JVM的Classloader

 
阅读更多
java源代码编译以后生成的class文件如何跑到JVM中的呢?对,就是Classloader把她们加载到JVM中去的。

接下来呢,就从3个方面对Classloader进行说明:Classloder的时机;Classloader的加载过程;Classloader的原理及分类。

1.Classloader的时机
类的生命周期:加载,验证,准备,解析,初始化,使用,卸载。
其中验证,准备,解析三个阶段可以称做连接(linking)
注意,以上的阶段中虽然开始时间分先后(注意:为了支持java中的运行时绑定解析阶段有可能在初始化后才开始执行),不过各个阶段通常都是交叉执行的。

什么时候需要加载一个类呢?虚拟机规范中明确规定了4种初始化阶段的触发时机(而加载,验证,准备自然需要在此之前开始):
1)遇到new、getstatic、putstatic或invokestatic这4个字节码指令时,如果类没有进行初始化,则需要先触发其初始化。生成4条指令最常用的java代码场景是:new一个对象时,读或者设置一个static字段时(final static除外)调用一个类的static方法时
2)使用java.lang.reflect包的方法对类进行反射调用的时候。
3)当初始化一个类,父类未初始化,则先初始化父类
4)jvm启动时,app执行的入口(包含main的类)会先被初始化。
以上4种场景被称为对一个类的主动引用,除此之外都是被动引用,不会触发初始化动作,举例:
1)通过子类引用父类的静态字段,不会导致子类初始化
2)通过数组定义来引用类,不会触发该类的初始化
3)常量(static final)在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,不会触发该类初始化

注意:接口和类有不一样的地方,就是一个类初始化前会要求其所有父类先初始化,但是接口在初始化时,并不要求其父接口全部都完成初始化,只有当真正使用父类接口(如引用接口中定义的常量)时才初始化。

2.Classloader的加载过程
1)类加载:
步骤:(1)通过一个类的全限定名来获取定义此类的二进制流
      (2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
      (3)在java堆中生成一个代表该类的java.lang.Class对象,作为方法区数据的操作入口

其中,被加载的class有很多种来源,举例:从ZIP等class文件包中读取;在运行时生成,如通过动态代理产生的代理类;有其他文件生成的class,如JSP应用等等。

2)连接:连接又分为以下几个步骤
(1)验证:
验证是连接阶段的第一步,是为了确保class文件的字节流符合JVM的规范。通常有4个阶段的验证过程:文件格式验证、元数据验证、字节码验证、符合引用验证。
1》文件格式验证:是否符合Class文件规范格式,符合才能进入方法区
2》元数据验证:是否符合Java语言规范的要求,主要进行字节码的语义分析
3》字节码验证:对类的方法体进行校验,主要进行数据流和控制流的分析
4》符合引用验证:最后一个阶段的校验发生在JVM将符合引用转换成直接引用(下文有提到)的时候

(2)准备:该阶段正式为类(static,不过final static--会直接赋=号后面的值,除外)变量分配内存并设置类变量默认值(这个时候没有实例变量什么事,因为还没有实例)

(3)解析:把常量池内的符合引用(只是和内存无关的符号标记)转换为直接引用(内存地址的引用)。解析的动作主要针对类或接口、字段(static)、类方法(static方法)、接口方法4类符合引用进行,分别对应于常量池的CONSTANT_Class_info,CONSTANT_Fieldref_info,CONSTANT_Methodref_info及CONSTANT_INterfaceMethodref_info四种常量类型。
  
3)类的初始化:将类的静态变量(static)赋予正确的初始值,这个初始值是开发者自己定义时赋予的初始值,而不是默认值。

类的初始化阶段是类加载的最后一步,前面的类加载过程中,除了加载阶段用户应用程序可以通过自定义类加载器参与之外,其他的工作都是由JVM主导和控制的。到了初始化阶段,才真正开始执行类中定义的Java程序代码。

3.类加载器的分类

注意:对于任意一个类,都需要有加载它的类加载器和这个类本身一同确立其在Java虚拟机中唯一性(也就是说,即使同一个class文件,若不同的classloader去加载,在JVM中就是两个不同的类)。

1)符合双亲委派模型的类加载器
主要分为三类:
(1)启动类加载器(Bootstrap ClassLoader)
这个类加载器负责将放到%JAVA_HOME%/lib目录中的,或被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的类库加载到JVM内存中。启动类加载器无法被Java程序直接使用。

(2)扩展类加载器(Extension ClassLoader)
这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载%JAVA_HOME%/lib/ext目录中的,或被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。

(3)应用程序类加载器(Application ClassLoader)
这个类加载器由sun.misc.Launcher$AppClassLoader来实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法返回的值,所有一般也成为系统类加载器。它负责加载用户路径(ClassPath)中所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下,这个就是程序中的默认类加载器。

双亲委派模型(Parents Delegation Model),要求除了顶层的启动类加载器外,其余的类加载器都应该有自己的父类加载器。这里的父子关系是通过组合来实现。

工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需要的类)时,子类加载器才会尝试自己加载。

双亲委派模型对应保证java程序的稳定运行很重要,但他的实现却非常简单,代码都集中在java.lang.ClassLoader的loadClass()方法中,
   
protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    c = parent.loadClass(name, false);
		} else {
		    c = findBootstrapClass0(name);
		}
	    } catch (ClassNotFoundException e) {
	        // If still not found, then invoke findClass in order
	        // to find the class.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
    }

执行逻辑:先检查是否被加载过,若没有则调用父加载器的loadClass()方法,若父加载器为空则默认启动类加载器为父加载器,如果父加载器加载失败(抛出ClassNotFoundException),再调用自己的findClass()方法进行加载。

2)OSGi的类加载器
OSGi实现模块化热部署的关键则是它自定义的类加载器的实现。每一个程序模块(Bundle)都有一个自己的类加载器,当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热替换。
是OSGi环境下,类加载器不再是双亲委派模型中的树状结构,而是进一步发展为网状结构,当收到类加载请求时,OSGi将按照如下的顺序进行类的搜索:
(1)将以java.*开头的类,委派给父类加载器加载;
(2)将委派给列表名单(org.osgi.framework.bootdelegation)内的类,委派给父类加载器加载;
(3)将Import-package列表中的类,委派给Export这个类的Bundle的类加载器加载;
(4)将Required-Bundle列表中的类,委派各个类对应Bundle的类加载器加载;
(4)查找当前Bundle的ClassPath,使用自己的类加载器加载;
(5)查找类是否在自己的Fragment Bundle中,如果在,则委派给Fragment Bundle的类加载器加载
(6)查找Dynamic Import(动态导入)列表的Bundel,委派给对应Bundle的类加载加载
(7)否则,类查找失败
分享到:
评论

相关推荐

    JVM ClassLoader简析

    ClassLoader是JVM中的一个重要组件,它的主要任务是加载类的二进制数据,转换为Class对象,并供Java应用程序使用。本文将深入浅出地探讨JVM ClassLoader的工作原理和相关知识点。 首先,ClassLoader可以分为三种...

    JVM.zip_JVM代理_classloader

    而JVM代理(JVM Agent)和类加载器(ClassLoader)则是两个关键的概念,它们对于深入理解Java应用程序的运行机制至关重要。 **JVM代理** JVM代理是一种在JVM启动时或者运行时插入额外功能的方式,它允许开发者在不...

    推荐一些JVM原理,JVM调优,JVM内存模型,JAVA并发 电子书1

    1. JVM原理:JVM的工作原理涉及类加载器(ClassLoader)、类文件(ClassFile)、内存管理及垃圾收集机制。类加载器负责将.class文件加载到内存中,为程序的运行准备数据结构。内存管理涉及JVM内存区域,包括堆、栈、...

    ClassLoader运行机制 自己写的

    在Java虚拟机(JVM)中,类加载器(ClassLoader)是至关重要的组成部分,它负责查找和加载类的字节码文件。理解ClassLoader的工作机制对于深入掌握Java应用程序的运行至关重要。这里我们将详细讨论ClassLoader的运行...

    Java ClassLoader学习总结

    Java ClassLoader学习总结 Java 类加载机制是 Java 中一个非常重要的机制,它负责加载 Class 文件到 JVM,以供程序使用。ClassLoader 是 Java 中的一个抽象类,它的主要作用是加载 Class 文件到 JVM 中。...

    JVM必知必会

    - **Bootstrap ClassLoader**:JVM级别的类加载器,负责加载`$JAVA_HOME/jre/lib`下的所有类库,不由Java实现,开发者无法直接操作。 - **Extension ClassLoader**:负责加载Java平台扩展功能的jar包,如`%JRE_HOME/...

    探索JVM底层奥秘ClassLoader源码分析与案例讲解

    2. **自定义ClassLoader**:在Java中,我们可以创建自定义的ClassLoader来实现特定的类加载策略。例如,可以从网络、数据库或者其他非标准位置加载类。 3. **类加载过程**:ClassLoader的加载过程包括加载(Loading...

    狂神说JVM探究.rar

    2. **类加载机制**: - 类的生命周期包括加载、验证、准备、初始化和卸载五个阶段。 - 双亲委派模型:类加载器在加载类时,会将任务委托给父类加载器,直到Bootstrap ClassLoader。 3. **内存区域**: - 程序...

    深入JVM内核—原理、诊断与优化视频教程-2.JVM运行机制

    2. **内存区域划分**:JVM内存分为堆内存和栈内存,其中栈内存又包括方法区、虚拟机栈、本地方法栈。堆内存用于存储对象实例,而栈内存则存储线程私有的局部变量、方法参数和运算结果。方法区存储类的信息,如常量池...

    JVM原理讲解和调优,详细讲解JVM底层

    JVM提供了三种类加载器:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader,分别用于加载Java核心类库、扩展类库和应用程序类库。此外,JVM还支持自定义类加载器,以便于实现特定的加载逻辑...

    深入理解ClassLoader工作机制.docx

    2. **验证**:验证是确保加载的类符合Java语言规范,不会破坏JVM的安全性。它检查字节码的格式、数据流和操作符计算、类和字段的访问控制等。 3. **准备**:在准备阶段,JVM为类的静态变量分配内存,并将其初始化为...

    classloader

    通过创建自定义ClassLoader,你可以定制JVM,使类文件的引入方式完全重新定义,这提供了很多实用和有趣的可能。这篇教程将对Java ClassLoader进行概述,并指导你构建一个示例ClassLoader,该ClassLoader可以自动编译...

    JAVA虚拟机(JVM)规范(中文版).rar

    1. **类装载器(ClassLoader)**:负责查找和加载类文件到JVM内存中。 2. **运行时数据区(Runtime Data Area)**:包括方法区、堆、虚拟机栈、本地方法栈和程序计数器。 3. **执行引擎(Execution Engine)**:执行...

    06.JVM原理讲解和调优.pdf

    JVM 的类加载是通过 ClassLoader 及其子类来完成的,类的层次关系和加载顺序可以由下图来描述: 1. Bootstrap ClassLoader:负责加载 $JAVA_HOME 中 jre/lib/rt.jar 里所有的 class。 2. Extension ClassLoader:...

    JVM基础.doc

    **ClassLoader** 负责加载ClassFile到JVM中,它遵循双亲委派模型。常见的ClassLoader包括Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader。 #### 四、内存模型、锁与同步 **Java内存模型** 主要...

    慢慢琢磨jvm 经典

    JVM由多个关键组件构成,包括类加载器(ClassLoader)、执行引擎(ExecutionEngine)和本地接口(NativeInterface): 1. **类加载器**:负责将类文件加载到内存中。它遵循严格的格式规范,确保加载的`.class`文件...

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

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

    java基础之JVM

    2. **扩展类加载器**(Extension ClassLoader):负责加载扩展目录下的类库,如`JAVA_HOME/jre/lib/ext`。 3. **应用程序类加载器**(Application ClassLoader):最常用的一种,负责加载用户类路径(ClassPath)中...

    JVM配置资料JVM配置资料

    2. **新生代与老年代的细分**: - **新生代**又分为Eden区和两个Survivor区(From Space和To Space),大部分对象在Eden区被创建,经历Minor GC后存活的对象会转移到Survivor区。 - **老年代**在Major GC或Full GC...

Global site tag (gtag.js) - Google Analytics