开发者社区> javahongxi> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

【转载】JVM类加载机制小结

简介:
+关注继续查看

本文转载自http://shift-alt-ctrl.iteye.com/blog/1845137

 

一.类加载   

    虚拟机把class文件加载至内存之后,对字节码数据进行校验/解析/初始化等操作,最终形成可被VM直接使用的java类型,这就是虚拟机类加载机制.类的加载完全可以在运行时进行,这给VM提供了动态加载类提供了可行性.

    类生命周期过程大概分为:加载-->校验-->解析-->初始化-->使用-->卸载;类在被"使用"之前必须进行前4个阶段,其中初始化工作可以被延迟进行,直到类需要创建实例/static方法或属性被调用(非编译常量)/反射机制中使用类的成员(Member)时被触发.

  1. 加载:通过类的全限定名的方式获取class文件的字节流.事实上,加载器可以从任何类型文件(zip,jar,txt等)或者网络中获取class字节流.参见ClassLoader类
  2. 校验:检查加载至内存的字节流是否符合当前JVM的规范要求,字节流信息需要被当前JVM(考虑到JVM的版本问题)正确的识别,包括字节流的格式/字节码的语义(语法)/类的继承关系/变量的声明合法性等进行全面校验,如果校验成功,则表明此class字节流是安全的/没有被修改的/可以被正常使用的.
  3. 准备:准备阶段是一个过渡阶段,在类文件校验合法之后,将会得出类的结构图,此时有必要对类的属性(static)进行默认值设定,比如static int默认为0,即使指定了值.不过对于final类型的,将会以"常量"特例被处理,直接持有原始值.
  4. 解析:解析阶段是JVM将常量池中的符号引用转换成直接引用的过程.
  5. 初始化:到此为止,一个类的"前戏"工作基本结束,接下来就可以"服务"了,此时类的属性(static)将会被设定为用户指定的值(区别于准备阶段),而且还会执行类的static区块.同时也会连带执行父类的static区块和静态属性的值初始化.对于类的static区块在多线程环境中被同步执行,如果有多个线程同事执行static区块,事实上最终只会在有一个线程执行.

二.类加载器

    对于任意一个类,它的唯一性将有它的类加载器和其类型来决定;如果一个类被多个classLoader加载(最终执行load操作的classLoader必须不同),那么它们最终获得的class引用将不相等(即"!="),即使用==,equals(),instanceof,isInstance(),isAssignableFrom()都得不到预期的值,事实上可以简单的认为,他们是不同的"类"(类型).

  1. 引导类加载器:Bootstrap-classLoader,此类主要负责加载JAVA API,即处于$JAVA_HOME$\lib下的class文件,这些lib位置可以在外部通过-Xbootclasspath指定,但是此目录下的jar文件不能被重命名或者人为增加,否则将不能被正常加载;引导类加载器不能被java程序获得,尝试获得引导类加载器将返回null.
  2. 扩展类加载器:负责加载$JAVA_HOME$\lib\ext目录下的class,开发者可以人为的在此目录下添加jar文件,以便被此JVM之上的所有应用所收益.此加载器可以被程序获取,一般为classpath类加载器的父类.(sun.misc.Launcher$ExtClassLoader)
  3. 应用类加载器:Application ClassLoader,负责加载应用的classpatch下的所有class文件,其中ClassLoader.getSystemClassLoader()获得的就是此加载器.(sun.misc,Launcher$AppClassLoader);自定义类加载器的父加载器一般设定为它.

JVM并没有使用继承关系来组织这三种类加载器,而是采取了组合关系(即classLoader.setParent(...)).

    JVM类加载过程和类关系维护采取了"双亲委派模型":对于任何类加载器(包括自定义类加载器)对于指定类的加载,首先交付给"父-类加载器"查找或加载,如果父-类加载器已经加载则直接获取class引用,否则继续传递当前类加载器的父-类加载器,直到引导类加载器,如果此时引导类加载器也没有持有class信息,则抛出异常(异常信息只作为中断信号),此时当前类加载器(直接接收加载请求的类加载器,比如自定义类加载器)将会尝试加载类信息...通过这种"委派关系",能够巧妙的(当然不是最佳的手段)规避类被重复加载的可能.

 

三.编译与泛型

    java中的泛型,是伪泛型,只是简单的在API级别做了"模样",但是对于类的编译过程,则会导致泛型类型的擦除,即编译过程或者编译之后的文件中,最终泛型仍然以"原生类型"表示.即在运行时无法直接还原"泛型",java还支持了反射机制,为了让反射机制能够和"泛型"配合,那么java最终提供了Generic(例如GenericArrayType)和ParameterizedType来配合获得泛型(和参数化类--类型)的信息,这些信息虽然在编译时被擦除,但是元数据(metadata)仍然被有效的class文件中.

    例如:List<Integer>在编译之后,API级别上就成了List,"丢失"了参数化的信息.那么方法 void invoke(List<Integer> list) 和void invoke(List<String> list),那么将不能共存在一个类中,因为编译之后它们是一样的.(识别方法的特性,有方法签名 + 参数列表,而定);但是还有一中特例,如果方法的参数列表中或者返回值中或者当前类是参数化的,那么对于方法的返回值类型也参与了"方法标识";例如上述两个方法,如果第二个方法改成Integer invoke(List<String> list)或者<T> T invoke(List<T> list)将被成功编译.

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【底层原理之旅—JVM类加载机制的重塑分析】|Java 刷题打卡
【底层原理之旅—JVM类加载机制的重塑分析】|Java 刷题打卡
0 0
别再乱看教程了!从源码剖析JVM类加载机制,打通双亲委派机制!
别再乱看教程了!从源码剖析JVM类加载机制,打通双亲委派机制!
0 0
Jvm 类加载机制解析,一起来了解神秘的类加载机制吧
当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过 加载,连接,初始化,这三个步骤对类进行初始化,如果没有意外,JVM 将会连续完成这三个步骤,所以有时也称为类初始化。
0 0
【Jvm】Jvm类加载机制
类加载时机 虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型,这就是虚拟机的类加载机制。 在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的
0 0
JVM类加载机制
类的加载机制是指把编译后的.class类文件的二进制数据读取到内存中,并为之创建一个java.lang.Class对象,用来封装类在元数据空间的数据结构。
0 0
JVM内存区域划分_JVM类加载机制_双亲委派模型_垃圾回收策略GC(JVM)
JVM内存区域划分_JVM类加载机制_双亲委派模型_垃圾回收策略GC(JVM)
0 0
JVM从入门到入土之JVM的类加载机制(下)
前言 文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820… 种一棵树最好的时间是十年前,其次是现在
0 0
JVM从入门到入土之JVM的类加载机制(上)
前言 文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820… 种一棵树最好的时间是十年前,其次是现在
0 0
面试必问的 JVM 类加载机制,你懂了吗?
本次带来JVM 的另一块重要内容,类加载机制,不废话,直接开怼。
0 0
+关注
javahongxi
京东技术 www.toutiao.im
文章
问答
文章排行榜
最热
最新
相关电子书
更多
JVM实战
立即下载
JVM的GC
立即下载
基于JVM的脚本语言开发、运用实践
立即下载