JVM学习(一):类加载器

java程序运行时,我们肯定需要由一个类调用另外一个类,当另外一个类在内存中不存在时,便会报错。而加载类这个功能则由classLoader来实现。同时classLoader实现了java动态加载类的功能

jvm中的classLoader主要由四个部分组成

Bootstrap ClassLoader:引导类加载器主要加载了JAVA中的核心API,\lib或者-Xbootclasspath指定的类,它通过C++来实现,并且嵌入在JVM中,在JVM运行时便创建一个Bootstrap ClassLoader来加载核心类库,并且创建ExtensionClassLoader 和App ClassLoader
Extension ClassLoader:拓展类加载器主要用来拓展类库,默认加载包括JAVA_HOME/jre/lib/ext/下的所有jar
Application ClassLoader:应用类加载器,主要用来加载应用程序classpath目录下的所有jar和class,这个是加载用户代码的ClassLoader
最后一个是用户自定义的类加载器,我们看以上的三个加载器可以发现,他们加载的是jre和本地应用程序下的类和class。但是当我们需要调用服务器上的类库怎么办,那就需要我们自定义类加载器来加载。

类加载器的特点:
阶级结构:每个类加载器都有一个父类加载器的引用(不是继承关系,是包含关系)Bootstrap Class Loader是所有类加载器的父类加载器
有限可见:一个子类加载器可以发现父类加载器的类,而父类加载器不能发现子类加载器的类。
不可卸载:一个类加载器可以加载一个类,但是不能卸载他,除非你删除当前类加载器并且创建一个新的。
双亲委派模式
双亲委派模式基于阶级结构的一种结构,通过这种模式,可以有效地避免类的重复加载。我们先看源码
protected Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 首先检查这个类是否被加载过
            Class c = findLoadedClass(name);
//如果没有被加载过
            if (c == null) {
                long t0 = System.nanoTime();
                try {
//检查这个加载器是否有父类加载器
                    if (parent != null) {
//如果有父类加载器,交给父类加载器加载
                        c = parent.loadClass(name, false);
                    } else {
//如果没有父类加载器,交给BootstrapClass加载(因为Bootstrap属于最上级加载器但在代码中不是
//父类加载器
                        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;
        }
    }

借用一张别人的图片: http://blog.csdn.net/xyang81/article/details/7292380
JVM学习(一):类加载器_第1张图片
我们可以看出,其实就是类加载器一层一层向委托,然后从上往下尝试加载。

类的加载过程:
JVM学习(一):类加载器_第2张图片
Loading:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象
Verifying(验证):检查这个类是否符合Java语法规则和JVM的规则,这是类加载过程中最耗费时间的部分
Preparing:为static的变量分配内存,并且将其初始值分配为0,实际值在初始化时赋值,注意:final的变量在编译时便分配好
Resolving(解析):主要将常量池中的符号引用替换为直接引用的过程
initializing(初始化):执行静态初始化器和初始化静态成员变量。

参考资料:http://blog.csdn.net/javazejian/article/details/73413292
http://blog.csdn.net/xyang81/article/details/7292380
https://dzone.com/articles/jvm-architecture-explained
http://www.cubrid.org/blog/understanding-jvm-internals

你可能感兴趣的:(java学习)