zoukankan      html  css  js  c++  java
  • jvm类加载

    类加载流程

    类加载流程

    加载:

    1. 通过一个类的全限定名来定义此类的二进制字节流
    2. 将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构
    3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

    验证:

    1. 验证class字节流,确保class文件中的字节流包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当做代码运行后不会危害虚拟机自身的安全;

    准备:

    1. 正式为类中定义的变量(即静态变量,static修饰的变量)分配内存并设置类变量的初始值的阶段;

    解析:

    1. 解析阶段是java虚拟机将常量池内的符号引用替换为直接引用的过程;

    类加载器

    启动(引导)类加载器(Bootstrap Class Loader): 负责加载jre的lib目录下的核心类库,比如rt.jar,charsets.jar等

    扩展类加载器(Extension Class Loader): 负责加载jre的lib目录下的ext扩展目录中的jar类包;

    应用程序类加载器(Application ClassLoader): 负责加载Classpath路径下的类包;主要加载自己写的类

    自定义加载器: 加载自定义路径下的类包;

    示例:

    
    public class TestJDKClassLoader {
        public static void main(String[] args) {
            System.out.println(String.class.getClassLoader());
            System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName());
            System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName());
            System.out.println();
            ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
            ClassLoader extClassLoader = appClassLoader.getParent();
            ClassLoader bootstrapLoader = extClassLoader.getParent();
            System.out.println("the appClassLoader:"+appClassLoader);
            System.out.println("the extClassLoader:"+extClassLoader);
            System.out.println("the bootstrapLoader:"+bootstrapLoader);
            System.out.println();
            System.out.println("bootstrapLoader 加载以下文件:");
            URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
            for (URL urL : urLs) {
                System.out.println(urL);
            }
            System.out.println();
            System.out.println("extClassLoader 加载以下文件:");
            System.out.println(System.getProperty("java.ext.dirs"));
            System.out.println();
            System.out.println("appClassLoader加载以下文件:");
            System.out.println(System.getProperty("java.class.path"));
        }
    }
    
    
    null
    sun.misc.Launcher$ExtClassLoader
    sun.misc.Launcher$AppClassLoader
    
    the appClassLoader:sun.misc.Launcher$AppClassLoader@18b4aac2
    the extClassLoader:sun.misc.Launcher$ExtClassLoader@7ea987ac
    the bootstrapLoader:null
    
    bootstrapLoader 加载以下文件:
    file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/resources.jar
    file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/rt.jar
    file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/sunrsasign.jar
    file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/jsse.jar
    file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/jce.jar
    file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/charsets.jar
    file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/jfr.jar
    file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/classes
    
    extClassLoader 加载以下文件:
    C:Program FilesJavajdk1.8.0_181jrelibext;C:WindowsSunJavalibext
    
    appClassLoader加载以下文件:
    ....部分省略
    C:Program FilesJavajdk1.8.0_181jrelib
    t.jar;
    G:IdeaProjectsjava-studyclass-loader	argetclasses;
    D:UsershelloAppDataLocalJetBrainsToolboxappsIDEA-Uch-0193.6911.18libidea_rt.jar
    
    1. appClassLoader的parent是extClassLoader;extClassLoader的parent为null;
    2. 各个类加载器加载的jar很多都是重复的;那么如何避免重复加载的呢?

    双亲委派模型

    双亲委派模型

    下面是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 { // 使用BootstrapClassLoader来加载
                            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); // 调用自己的findClass来查找;这个方法为空,自定义加载器重写;
    
                        // 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流程

    为什么设计双亲委派模型

    1. 沙箱安全机制,Java核心类库交由指定类加载器加载,防止核心类库被篡改;
    2. 避免重复加载,当父加载器已经加载了,就不用在加载了;

    自定义类加载器

    从上面的流程图可以看出,自定义类加载器主要有两步;

    1. 继承ClassLoader;
    2. 重写findClass方法;

    下面按照上面的步骤自定义一个类加载器:

        ClassLoader classLoader = new ClassLoader() {
            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                String path = name.replaceAll("\.", "/");
                try (FileInputStream is = new FileInputStream("H:/test/" + path + ".class")) {
                    byte[] b = new byte[is.available()];
                    is.read(b);
                    return defineClass(name, b, 0, b.length);
                } catch (IOException e) {
                    throw new ClassNotFoundException();
                }
            }
        };
    

    这就是个简单的类加载器了;注意双亲委派模型的流程,这里需要注意的是最后是否会调用到findClass方法;

    破坏双亲委派模型

    过双亲委派模型并不是一个具有强制性约束的模型,而是 Java 设计者推荐给开发者们的类加载器实现方式。在 Java 的世界中大部分的类加载器都遵循这个模型,但也有例外的情况;
    这里只是提一下,具体需要看《深入Java虚拟机jvm高级特性与最佳实践》或者网上的博客;

  • 相关阅读:
    第一次实验
    pta12
    《暗时间》读书笔记
    案例分析
    软件工程第二次作业
    阅读任务
    20210311_软工_准备工作
    学习总结
    第十四周学习总结&实验报告
    第十三周课程总结
  • 原文地址:https://www.cnblogs.com/guoyuchuan/p/14814940.html
Copyright © 2011-2022 走看看