JVM类加载机制及源码分析

JVM类加载机制

当我们运行某个类的main函数时,首先需要通过类加载器将主类加载到JVM中去。

类加载过程

加载

在硬盘上找到对应的.class文件,并且通过IO 读入

验证

校验字节码文件的正确性

准备

给类的静态变量分配内存,并赋予默认值

解析

将符号引用替换为直接引用,该阶段会把一些静态方法(静态方法,例如main()方法,替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换成直接引用)

符号引用&直接引用

在类的加载过程中的解析阶段,Java虚拟机会把类的二进制数据中的符号引用 替换为 直接引用,如Worker类中一个方法:

public void gotoWork(){
     car.run(); //这段代码在Worker类中的二进制表示为符号引用        
}

在Worker类的二进制数据中,包含了一个对Car类的run()方法的符号引用,它由run()方法的全名 和 相关描述符组成。在解析阶段,Java虚拟机会把这个符号引用替换为一个指针,该指针指向Car类的run()方法在方法区的内存位置,这个指针就是直接引用。

初始化

对类的静态变量初始化为指定的值,执行静态代码块

使用

卸载

类加载器

启动类加载器

是由C++实现的,这个类加载器负责放在\jre\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的类库。用户无法直接使用。

扩展类加载器

这个类加载器由sun.misc.Launcher$AppClassLoader实现。它负责\jre\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。用户可以直接使用。

应用程序类加载器

这个类由sun.misc.Launcher$AppClassLoader实现。是ClassLoader中getSystemClassLoader()方法的返回值。它负责用户路径(ClassPath)所指定的类库。用户可以直接使用。如果用户没有自己定义类加载器,默认使用这个。

自定义加载器

用户自己定义的类加载器。

双亲委派机制

当需要加载一个类的时候首先是找到应用类加载器去加载,应用类加载器会向上委托给扩展类加载器,扩展类向上委托给启动类加载器,启动类加载器在核心类库中(\jre\lib)找不到该类时,会让扩展类自己加载,扩展类加载器(\jre\lib\ext)也没找到该类时就会让应用类加载器自己到(classpath)加载,这就是双亲委派机制。如下图示意:
JVM类加载机制及源码分析_第1张图片

接下来我们看看源码的实现,由于ExtClassLoader中没有覆写loadClass()方法,而AppClassLoader的loadClass()方法最终是指向ClassLoader类中的loadClass()这个方法,所以我们直接看ClassLoader中的代码

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) {
                    // 如果父类不为空,调用parent(该parent不是通过extend来的父类,而是在Launcher类中指定的)
                    // 的loadClass
                    c = parent.loadClass(name, false);
                } else {
                    // 由于BootstrapClassLoader是C++实现的,所以ExtClassLoader的parent赋值是null
                    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.
                // 如果上面的classLoader都没找到就自己找
                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.避免类的重复加载

你可能感兴趣的:(JVM,java,jvm)