JVM之类加载

类是什么时候被加载的?

Java虚拟机规范中是没有指定什么时候加载类的,而是交给具体的虚拟机完成的。HotSpot虚拟机是按需加载,是在需要该类的时候加载这个类的。

类的加载过程(生命周期)

1、加载

classpath、jar包、网络或某个磁盘位置下的类的class二进制字节流读进来,在内存中生成一个代表这个类的class二进制元信息放在元空间

2、链接
验证

验证class文件字节流中包含的信息符合《JVM虚拟机规范》的全部约束要求,来保证虚拟机的安全。

准备

类常量赋值,类变量赋值的初始值,如int类型0,boolean对应false

解析

将符号引用变成直接引用

3、初始化

当new一个类的对象,访问修改调用类的静态属性,通过放射调用或初始化类都会完成类的初始化。

4、使用

使用这个类

5、卸载

1、类的所有实例都被GC,或类的classLoader也被GC。
2、类没有被任何地方引用。
很少卸载。

类被初始化的过程

准备阶段给静态常量赋值,给变量赋值默认值,初始化阶段给变量赋值实际值,静态代码块也是在初始化时执行,而变量和代码块和构造方法是在对象创建的时候执行的。当存在继承关系的时候,会先加载父类的相关信息,静态常量,静态变量等。

类加载器的三层结构

在这里插入图片描述

BootstrapClassLoader(启动类加载器)

加载rt.jar,resource.jar,charsets.jar,和-Xbootclasspath指定路径下的存在的类库

ExtClassLoader(扩展类加载器)

加载jre/lib/ext下的类库,和java.ext.dirs系统变量所指定路径下的类库

AppClassLoader(应用程序类加载器)

加载classpath下所有的类库
注:三层类加载器不是继承关系

双亲委派模型

在这里插入图片描述
当一个类加载器接受到了加载类的请求,它不会直接加载这个类,而是将这个类委派为上层类加载器去加载,因此所有的加载请求最终都会到最上层的类加载器,只有当上层类加载器反馈说自己无法加载这个类时,才会传递给下层类加载器去完成。
好处: 避免jdk核心类库被篡改,比如rt.jar中的类,外界手写的类进行加载的时候都会传递给上层类加载器去加载,所有都会去加载核心类库的类,而不是篡改之后的类。同时可以避免重复加载,保证了类的唯一性。
如果需要打破双亲委派模型,需要自己重写类加载器,重写LoadClass方法,使其不进行双亲委派。重写类加载器且不破坏双亲委派模型,可以重写findclass方法
双亲委派模型源码:

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;
        }
    }

loadClass():主要进行类加载的方法,其中实现了双亲委派模型
findClass():根据名称或位置加载class字节码
defineClass():将字节码转换为class

class.forName,classLoader

class.forName加载类的时候会初始化类,而使用classLoader加载类的时候,不会初始化类。

Tomcat中的类加载机制

在这里插入图片描述
白色部分为扩展部分
其中重写了loadClass方法,并且打破了双亲委派模型,先自己尝试加载,自己加载不了然后交给上级加载,目的是优先加载web应用自己定义的类。那Tomcat为什么要打破双亲委派模型? 因为一个Tomcat可能部署多个web应用,要保持不同应用的私有jar包隔离,通用jar包共享,保证tomcat服务不受部署的web应用影响,同时需要支持JSP的热加载与热部署。
热加载: 是指在不重启服务的情况下让更改的代码生效,可以显著的提升开发和调试的效率,是基于Java的类加载器实现的,但是由于不安全性,很少用于正式的生产环境、
热部署: 是指在不重启服务的情况下重新部署整个项目,比如Tomcat中热部署就是在程序运行的时候如果修改了war包中的代码,那么就会删除war包之前解压的文件夹,重新解压新的war包生成文件夹。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值