JVM类加载机制

什么是类加载过程

JVM类加载流程为:加载——连接(连接又分为:验证,准备,解析)——初始化
各个步骤的含义

加载

将javac编译后的class文件加载到Java虚拟机的方法区中。
加载的过程分为三步:
第一步通过类的全限定名获取相应的二进制字节流,
第二步将二进制字节流转换为方法区可运行的数据结构,
第三步在内存中生成一个代表这个类的java.lang.Class对象,作为方法区中这个类的访问入口。

连接

连接分为三步:
验证:主要是确保Class文件中的字节流中包含的信息是否符合jvm的规范,是否有安全隐患。主要验证四个方面:文件格式验证,元数据验证,字节码验证,符号引用验证。
准备:为类变量(static修饰的静态变量)在方法区内分配内存,以及初始赋值。
解析:虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符这7类符号引用进行。

初始化

正式给类变量赋正确的初始值。在准备阶段,变量已经赋过一次系统要求的初始零值,而在初始化阶段,则会根据程序员通过程序制定的主观计划(也就是我们在代码中给变量赋的值)去初始化类变量和其他资源。

什么是类的生命周期

而对于类的生命周期又在此流程上增加了两个流程:加载——连接(连接又分为:验证,准备,解析)——初始化——使用——卸载
为了方便理解我们可以将这个流程想象为以下的内容:
张三存了好久的钱想买一个手机,于是他在网上买了一个IPhone13 Pro Max 1TB 远峰蓝手机,下单就是(加载);怀着激动心情等了几天终于收到新手机(链接);收到手机后我们肯定不能直接使用,还有一些使用前的流程,看看手机屏幕有没有刮痕,电池有没有鼓包等等(验证);如果没有问题,我们贴膜,把手机卡从旧手机中拿出来,放到新手机中等等(准备);然后开机,开机过程中会解析我们的手机卡是移动、联调亦或者电信(解析);正常开启后我们就需要对手机进行数据同步呀等等(初始化);等都操作完我们就可以开心的用新手机了(使用);过了些许时间,张三又买了其他的手机,于是就把这个手机给卖了(卸载),至此该手机的使命就完成。

什么是双亲委派机制

当一个类加载器收到了类加载请求,不会直接去加载,而是将这个请求委派给父类,依次类推,请求都会被委派给顶级父类启动类的类加载器中,当无法完成请求(在其搜索范围内无法找到对应的类)才会将请求还给子类来加载,依次类推,直到完成请求或各个等级的类都无法完成请求而报错。
类加载源码如下:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 1、检查请求的类是否已经被加载过了
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 2、将类加载请求先委托给父类加载器
                    if (parent != null) {
                        // 父类加载器不为空时,委托给父类加载进行加载
                        c = parent.loadClass(name, false);
                    } else {
                        // 父类加载器为空,则代表当前是Bootstrap,从Bootstrap中加载类
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // 如果父类加载器抛出ClassNotFoundException
                    // 说明父类加载器无法完成加载请求
                }

                if (c == null) {
                    // 3、在父类加载器无法加载的时候,再调用本身的findClass方法来进行类加载
                    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;
        }
    }

为什么要使用双亲委派机制

使用双亲委派机制的好处是给类加载制定了一个规则,使其能够确定优先级,以及层次间的关系。如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个java.lang.Object 的类,并放在程序的 ClassPath 中,那系统中将会出现多个不同的 Object 类,Java 类型体系中最基础的行为也就无法保证,应用程序也将会变得一片混乱。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值