java类的装载

类的装载过程:

1 类加载
2 链接(验证-准备-解析)
3 初始化
首先是类加载过程:

    先是获取类的二进制流,转到内存的方法区(放置类的元数据,类型,方法,形参类型,返回值地址。。。),在堆中生成对应的java.lang.class对象。

再到链接:

    验证:文件格式验证(是否以0xCAFEBABE开头,版本号),元数据验证(是否有父类,object类等,是否有继承错误,方法是否实现,重写等),字节码校验(操作数栈,变量是否吻合,栈空间大小问题,跳转指令跳转到偏移量等问题),符号引用验证(权限验证,private,protected这种,检查常量池中描述的类或接口是否存在)。

    准备:会对全局变量进行初始值的设定(例如:private static int i=1 ,会先初始成0,在初始化<clinit>才会初始成1,除了private static final i = 1,一开始就会初始成1,final会特例)。

    解析:符号引用会替换为直接引用(符号引用指的是,若没有继承,默认是继承java.lang.object类,在这个类的常量池中有个字符串是java.lang.object,只是用来表示,直接引用是一段内存地址,指向真正的对象)。

    看过本书说过,引用不止有指向堆中得对象,还有种是在堆中有个句柄池,指向对象,引用指向句柄池。在进行gc回收算法的时候,对象发生地址改变,会对直接引用有影响,用句柄池的话,引用地址就不会变化了,我想这就是有些引用前面加final原因,使用句柄池后,在发生对象部分回收后在内存中移动,这时候修改同在堆的句柄池地址会比修改栈上的引用地址快。

最后初始化:

    执行类构造初始化<clinit>,给staic变量赋值,运行静态块,对象块,父类必须在之前先调用父类的<clinit>(<clinit>是线程安全的)。

类的装载器ClassLoader:

    ClassLoader是一个抽象类,ClassLoader的实例将读入java字节码将类装载入jvm,可以定制符合不同字节码流获取方式(可以从网络或文件加载),在装载负责加载阶段。

ClassLoader比较重要方法:loadClass()(根据类名去装载,返回类的信息),defineClass()(定义一个类,在形参传入类的二进制字节码),findClass()(loadClass回调方法,自定义装载器做法),findLoad()(查看是否是已装载类)

ClassLoader拥有四种:

    BootStrap ClassLoader(加载系统类 rt.jar)

    Extension ClassLoader(加载扩展类 lib/ext/*.jar)

    App ClassLoader(加载应用类,也就是我们自己写的类 ,classpath下)

    Custom ClassLoader(自定义加载器)

    除了第一个加载都有个Parent作为父亲,按照上面的排序进行 自底向上检查类是否加载(寻找需要加载的类是否在对应装载器的目录下,找不到会报ClassNotFoundException),自顶向下加载类(自上而下加载对应装载器路径下的类)。

protected synchronized Class<?> loadClass(String name,boolean resolve) throw ClassNotFoundException{
    //检查请求的类是否已经被加载过了
    Class c = findLoadedClass(name);
    if(c==null){
        try{
            if(parent!=null){
                c = parent.loadClass(name,false);
            }else{
                c = findBootstrapClassOrNull(name);
            }
        }catch(ClassNotFoundException e){
            //如果父类加载器抛出ClassNotFoundException说明父类无法完成类加载
        }
        if(c == null){
            c = findClass(name);
        }
    }
    if(resolve){
        resolveClass(c);
    }
    return c;
}

    上面这段代码是加载类,先是查找是否被加载,没有的话会去请求父类加载,这就是自顶向下的加载。

    使用(/-Xbootclasspath)指定应用类加载路径,最终会使用bootstrap加载器加载应用类(我们自己写的类),本来是使用app加载器加载。使用反射用app classloader先加载,就可以避免以上情况。

    双亲模式:顶层ClassLoader无法加载底层的ClassLoader类,是因为寻找加载类和加载类的方式的问题。但是在核心类rt.jar却有应用层的类的接口,这样会造成问题,这样就需要个上下文加载器(Thread.setContextClassLoader()),这只是个线程。

    双亲模式破坏:tomcat(先加载自身的.class),OSGi(可以进行模块化,热加载)

    热替换:系统无需重启,在类被替换后马上生效。

    内存溢出:生成对象过多。

    内存泄漏:对象无法回收。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值