java_类加载

4 min read

类加载

1 什么时候加载

类加载是惰性的,如果我们没用用到类,这个类就不会加载。如果类中有静态变量则会直接加载,如果new对象也会开始加载。

2 谁加载

类加载器。

BootstrapLoader加载rt包下的一些jdk基础的类,在启动的时候需要的很多类都是这里面的,他们由BootstrapLoader加载。

ExtClassLoader加载一些扩展类,例如ext包下的一些类是他加载的。

AppClassLoader加载classpath下各种用户类,入口main函数所在的类就是用户类,是由AppClassLoader加载。

三者为父子关系,但是Boot是Ext的父,Ext是App的父。原则上当前类中加载的对象,会优先用当前类的类加载器尝试加载。例如

class A{
    void test(){
        B b = new B();
        String c = new String();
    }
}

上面的用户类B的加载器是跟A类的加载器一样的,而rt类String的类加载器会先尝试A的类加载器,根据双亲委派最终用BootStrapLoader加载好的String类。

2.1 双亲委派

通俗讲,就是要加载类的时候找到了类加载器,但是不是立即用这个加载器加载。而是先判断当前类加载器的父类加载器是否加载过这个类,如果已经加载过了则直接返回父类加载器加载好的类对象,否则才用当前类加载器加载。

例如上面的B,先找到AppCL,找父Ext,未加载,找父Boot,未加载,最终决定由AppCL来加载。再比如上面的String,先找AppCL,找父Ext,未加载,找父Boot,String是rt中的类已经由Boot加载。所以直接返回的这个AppCL加载过的String类对象。即这里c这个对象的对象头中Klass指针,指向的Klass是Boot加载好的String对应的Klass。

3 怎么加载

加载class文件字节码->连接(验证、准备、解析)->初始化->[使用->卸载]。

主要涉及Metaspace部分,一个ClassLoader对应一部分Metaspace中的内存,这部分来放置类的元数据,例如Klass,itable,vtable等。当新的类加载的时候Metaspace就会变大,而当这个类加载器加载的所有对象和Class对象都被gc掉之后,也会将Metaspace清理,这个过程也是类卸载的过程。

4 应用场景

利用自定义类加载器解决冲突问题,之前讲过,参考这个项目,这也是阿里的Pandora容器干的事情。