JVM学习(一):类加载器

来源:互联网 发布:redis与mysql区别 编辑:程序博客网 时间:2024/04/30 01:09
java程序运行时,我们肯定需要由一个类调用另外一个类,当另外一个类在内存中不存在时,便会报错。而加载类这个功能则由classLoader来实现。同时classLoader实现了java动态加载类的功能

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

Bootstrap ClassLoader:引导类加载器主要加载了JAVA中的核心API,<JAVA_HOME>\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

我们可以看出,其实就是类加载器一层一层向委托,然后从上往下尝试加载。

类的加载过程:

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
原创粉丝点击