侧边栏壁纸
博主头像
liuxy博主等级

细水长流,吃穿不愁

  • 累计撰写 39 篇文章
  • 累计创建 30 个标签
  • 累计收到 6 条评论

目 录CONTENT

文章目录

【JVM专题】JVM类加载机制的三种特性

liuxy
2023-02-22 / 0 评论 / 0 点赞 / 181 阅读 / 1,231 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-02-22,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

全盘负责

当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
例如:系统类加载器AppClassLoader加载入口类(含有main方法的类)时,会把main方法所依赖的类及引用的类也载入,以此类推。“全盘负责”机制也可以成为当前类加载器负责机制。显然,入口类所依赖的类及引用的类的当前类加载器就是入口类的类加载器。(以上步骤只是调用了ClassLoader.loadClass(name)方法,并没有真正定义类。真正加载class字节码文件生成Class对象由“双亲委派”机制完成)

父类委托(双亲委派:向上检查)

“双亲委派”是指子类加载器如果没有加载过目标类,就委托父类加载器加载该目标类,只有父类加载器找不到字节码文件的情况下才从自己的类路径中查找并装载目标类。

“双亲委派”机制加载Class的具体过程:

  1. ClassLoader先判断该Class是否已加载,如果已加载,则返回Class对象;如果没有则委托给父类加载器。
  2. 父类加载器判断是否加载过该Class,如果已加载,则返回Class对象;如果没有则委托祖父类加载器。
  3. 以此类推,直到始祖类加载器(引用类加载器)。
  4. 始祖类加载器判断是否加载过该Class,如果已加载,则返回Class对象;如果没有则尝试从其对应的类路径下寻找class字节码文件并载入,如果载入成功,则返回Class对象;如果载入失败,则委托给始祖类加载器的子类加载器。
  5. 始祖类加载器的子类加载器尝试从其对应的类路径下寻找class字节码文件并载入,如果载入成功,则返回Class对象;如果载入失败,则委托给始祖类加载器的孙类加载器。
  6. 以此类推,直到源ClassLoader。
  7. 源ClassLoader尝试从其对应的类路径下寻找class字节码文件并载入,如果载入成功,则返回Class对象;如果载入失败,源ClassLoader不会再委托其子类加载器,而是抛出异常。

注:“双亲委派”机制只是Java推荐的机制,并不是强制的机制。
EC1FD6E6-18E2-4D93-87AF-0E2000419FF5

我们可以继承java.lang.ClassLoader类,实现自己的类加载器。如果想保持双亲委派模型,就应该重写findClass(name)方法;如果想破坏双亲委派模型,可以重写loadClass(name)方法。

缓存机制

缓存机制将会保证所有加载过的Class都将在内存中缓存,当程序中需要使用某个Class时,类加载器先从内存中寻找该Class,只有缓存区不存在时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这既是为什么修改了Class后,必须重启JVM,程序的修改才会生效,对于一个类加载实例来说,相同全名的类只加载一次,即loadClass方法不会被重复调用。

而这里我们JDK8使用的是直接内存,所以我们会到直接内存进行缓存。这也是我们的类变量为什么只会被初始化一次的由来。

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First,在虚拟机内存中查找是否已经加载过此类...类缓存的主要问题所在!!!
            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();
   					 //调用此类加载器所实现的findClass方法进行加载
                    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方法是当字节码加载到内存后进行链接操作,对文件格式和字节码验证,并为 static 字段分配空间并初始化,符号引用转为直接引用,访问控制,方法覆盖等
                resolveClass(c);
            }
            return c;
        }
    }
0
广告 广告

评论区