美文网首页
类加载机制

类加载机制

作者: laowangv2 | 来源:发表于2021-02-02 23:20 被阅读0次

    一、类加载的作用

    把class文件中的类加载到虚拟机中。什么时候加载呢?触发时机包括以下几种:

    1. 使用静态字段或静态方法,包括new的时候;
    2. 使用java.lang.reflect包的方法对类进行反射调用时;
    3. 初始化一个类时,首先确保初始化其父类;
    4. 虚拟机启动时,加载主类;
    5. 使用动态语言支持时

    二、类加载的流程

    1. 加载
      获取二进制字节流,转换成方法区的运行时数据结构,在内存生成一个class对象
    2. 链接
      • 验证
      • 准备
        分配内存,赋初始值
      • 解析
        符号引用替换成直接引用
    3. 初始化
      执行<clinit>()
    4. 使用
    5. 卸载
      需要:所有对象被gc,类对象没有被引用,类加载器被gc

    三、类加载模型

    双亲委派模型,先给parent load,load不到才会自己load

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

    使用这种模型的意义是:

    1. 防止混乱,避免同一个类被各种加载
    2. 保证虚拟机的安全,自己写一个java.开头的类自己加载,会抛出SecurityException

    四、类加载器

    1. BootstrapClassLoader
      c++实现,虚拟机的一部分,负责加载运行时需要的核心类库。例如存放在$JAVA_HOME/lib中并且能被虚拟机识别的类(如rt.jar包中的java.开头的类)
    2. ExtClassLoader
      加载$JAVA_HOME/lib/ext中的jar包,实现在sun.misc.Launcher中,他的parent是null,代表BootstrapClassLoader
    3. AppClassLoader
      加载用户路径(ClassPath)上指定的类库,也就是用户实现的类。同样实现在sun.misc.Launcher中,他的parent是ExtClassLoader

    五、一些著名的例子

    1. 线程上下文加载器
      起因是例如JNDI服务这样的服务接口作为java标准服务是由BootstrapClassLoader加载的,而其实现由独立厂商提供(SPI,Service Provider Interface)放在classpath下,BootstrapClassLoader无法加载,所以只好使用线程上下文加载器开个后门,默认为AppClassLoader

    相关文章

      网友评论

          本文标题:类加载机制

          本文链接:https://www.haomeiwen.com/subject/kqfetltx.html