java 虚拟机的类加载机制

一、类的加载

是指把描述类数据的class文件加载到内存,并进行数据校验、转换解析和初始化,形成可以被虚拟机直接使用的Java类型,成为虚拟机的类加载机制。java中类型的加载和连接都是在程序运行期间完成的。这样在加载时会增加一些性能开销,但是却为java程序提供了高度的灵活性。

二、类的生命周期七个阶段

加载(Loading)----验证(Verification)----准备(Preparation)----解析(Resolution)----初始化(Initialization)----使用(Using)----卸载(Unloading)

这些阶段通常时相互交叉地混合式进行的,通称会在一个阶段执行的构成中调用或激活另一个阶段。

加载(Loading)
加载阶段主要完成三件事情
1.通过一个类的全限定名来获取定义此为的二进制字节流。这个阶段是开发阶段可控性最强的阶段,因为加载阶段既可以使用系统提供的类加载器来完成,也可以由用户自定义的类加载器去完成,可以通过定义自己的类加载器去控制字节流的获取方式。比如可以从ZIP包读取,从网络获取,运行时计算生成,由其他文件生成,由数据库读取等等。
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3.在java堆中生成一个java.lang.Class对象,作为方法区的这些数据的访问入口。


验证(Verification)
1.文件格式的验证:验证字节流是否符合Class文件格式规范,并且能被当前版本的虚拟机处理。
2.元数据验证:对字节码描述的信息进行语义分析,以保证其描述的信息符合java语言规范的要求。
3.字节码验证:进行数据流和控制流分析。对类的方法体进行校验分析,保证被校验类的方法在运行时不会作出危害虚拟机安全的行为。
4.符号引用验证:对类自身意外的信息进行匹配性验证。


准备(Preparation)
正式为类变量(被static修饰的变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。

pubic static int value = 123;这阶段value的初始值不会被设置123,而是0,把value设置为123的动作在初始化阶段才会去执行。


解析(Resolution)
虚拟机将常量池内的符号引用替换为直接引用的过程。符号引用与虚拟机实现的内存布局无关,引用的目标不一定已经被加载到内存中。直接引用可以是直接指向目标的指针、相对偏移量或者一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中存在。


初始化(Initialization)
是类记载过程的最后一步,这个时后真正开始执行类中定义的java代码或者说是字节码。初始化阶段是执行类构造器<clinit>方法的过程。

什么时后开始类的加载虚拟规范并没有进行强制约束,但是如下四种情况必须立即进行类的初始化。
1. 遇到new,getstatic,putstatic和invokestatic这4条指令时,如果类没有初始化时,必须初始化类。
new----使用new关键字实例化对象
getstatic----读取一个类的静态字段
putstatic----设置一个类的静态字段
invokestatic----调用一个类的静态方法
以上这四种行为成为对一个类进行主动引用。除此之外的所有引用都不会触发类的初始化,成为被动引用。
2. 对类进行反射调用时。
3. 当初始化一个子类时,发现其父类没有初始化,则需先出发其父类的初始化。
4. 当虚拟机启动时,一个类包含main()方法时,当前类需要初始化。

三、三种类加载器

启动(Bootstrap)类加载器:启动类加载器是用本地代码实现的类加载器,它负责将JAVA_HOME/lib下面的核心类库或-Xbootclasspath选项指定的jar包等虚拟机识别的类库加载到内存中。由于启动类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用。。
扩展(Extension)类加载器:扩展类加载器是由Sun的ExtClassLoader实现的,它负责将JAVA_HOME/lib/ext或者由系统变量java.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。
系统(System)类加载器:系统类加载器是由Sun的AppClassLoader实现的,它负责将用户类路径变量所指的目录下的类库加载到内存中。开发者可以直接使用系统类加载器。

注:比较两个类是否相等,只有这两个类是由同一个类加载器加载的前提下才有意义。同一个路径下的class文件由不同的类加载器加载,那这两个类必定不相等。

四、双亲委派模型
要求除了顶层的启动类加载器之外,其余的类加载器都应当有自己的父类加载器。
工作过程:当一个类收到类加载请求时,它首先会把这个请求委派给父类加载器去完成。如果父类加载器无法完成加载,子类加载器才会去尝试加载。
这样做确保了java类随着它的类加载器一起具备了一种带有优先级层次的关系,它保证了Java体系中最基础的行为。例如java.lang.Object,它放在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给启动(Bootstrap)类加载器进行加载。如果没有使用双亲委派模型,由各个类自行去加载的话,如果用户也写了一个名称为java.lang.Object的类,并放在程序ClassPath中,那系统将出现多个不同的Object类,Java体系中最基础的行为也就无从保证。

所以,双亲委派模型对于保证java程序的稳定非常重要,实现非常简单。

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值