美文网首页
虚拟机类加载机制

虚拟机类加载机制

作者: JohnShen | 来源:发表于2017-03-09 06:01 被阅读43次

    虚拟机的类加载机制

    虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。

    类的加载过程:

    加载—>验证—>准备—>解析—>初始化

    加载:查找并加载类的二进制文件

    需要完成3件事:

    1. 通过一个类的全限定名来获取定义此类的二进制字节流
    2. 将这个字节流的金泰存储结构转为方法区的运行时数据结构
    3. 在内存中生成java.lang.Class对象,作为方法区这个类的各种数据的访问入口
    验证:确保被加载类的正确性
    • 文件格式验证:是否以魔数0xCAFEBABE开头
    • 元数据验证
    • 字节码验证
    • 符号引用验证
    准备:正式为类变量分配内存并设置类变量初始值,变量使用的内存在方法区分配。
    public static int value = 123; //在初始化阶段才赋值为123,准备阶段为0
    public static final int value = 123; //在准备阶段就被赋值为123
    
    解析:虚拟机将常量池内的符号引用替换为直接引用
    初始化:为类的静态变量初始化

    静态块中可以给静态变量赋值,但不允许访问,否则会提示“非法向前引用”。

    类加载器

    双亲委派模型

    启动类加载器 <— 扩展类加载器<— 应用程序类加载器<— 自定义类加载器

    工作过程:

    如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求的时候,子加载器才会尝试自己去加载。

    使用双亲委派模型的好处是:Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器加载这个类,最终都是委派给启动类加载器进行加载,因此,Object类在程序的各种类加载器环境中都是同一个类。

    先检查是否已经被加载过,若没有加载则调用父加载器的loadClass()方法,若父加载器为空则默认使用启动类加载器作为父加载器。如果父加载失败,抛出ClassNotFoundException异常后,再调用最的findClass()方法进行加载。
    双亲委派模型的代码在java.lang.ClassLoader.loadClass()中:

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

    Tomcat的Classloader体系结构

    CommonClassLoader <— CatalinaClassLoader
             ^—  SharedClassLoader<— WebAppClassLoader
    

    相关文章

      网友评论

          本文标题:虚拟机类加载机制

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