深入浅出JVM(二)之类加载器
1.类装载器(ClassLoader)
1. 负责加载class文件,将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构,ClassLoader只负责class文件的加载,
至于它是否可以运行,则由ExecutionEngine(执行引擎)决定 ,class文件在文件开头有特定的文件标示(32字节用16进制表示是"cafebabe")
2.类被加载到方法区中后主要包含 运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例的引用等信息。
1.1类装载器ClassLoader分类
虚拟机自带的加载器分为启动类加载器,扩展类加载器和应用程序类加载器
1.1.2启动类加载器
启动类加载器((Bootstrap)C++)也叫根加载器,是嵌在JVM内核中的加载器,该加载器是用C++语言写的,主要负载加载JAVA_HOME/lib下的类库,启动类加载器无法被应用程序直接使用
2.1.3扩展类加载器
扩展类加载器(ExtensionClassLoader)是用JAVA编写,主要负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目录下的所有jar包或者由java.ext.dirs系统属性指定的jar包.
2.1.3应用程序类加载器
应用程序类加载器(System classLoader):又称为系统类加载器,主要用于加载CLASSPATH路径下我们自己写的类,它的父加载器为Ext ClassLoader
2.2.loadClass的类加载过程
其中loadClass的类加载过程有如下几步:加载 >> 验证 >> 准备 >> 解析 >> 初始化 >> 使用 >> 卸载
1.2.1加载(Loading)
1.通过一个类的全限定名获取定义此类的二进制字节流
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.Class对象(此对象在堆中),作为方法区这个类的各种数据的访问入口
4.注意:主类在运行过程中如果使用到其它类,会逐步加载这些类。jar包或war包里的类不是一次性全部加载的,是使用到时才加载。
*补充:加载.c1ass文件的方式
·从本地系统中直接加载
·通过网络获取,典型场景:Web Applet
·从zip压缩包中读取,成为日后jar、war格式的基础
·运行时计算生成,使用最多的是:动态代理技术
.由其他件生成,典型场景:JSP应用
·从专有数据库中提取.class文件,比较少见
·从加密文件中获取,典型的防class文件被反编译的保护措施
1.2.1验证Verify)
目的在于校验字节码文件的正确性,主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
1.2.2准备(Prepare)
1.2.3解析(Resolve)
将常量池内的符号引用转换为直接引用的过程。
1.符号引用:
1) 以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义的定位到目标即可;
2)例如,在Class文件中它以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等类型的常量出现;
3)符号引用与虚拟机的内存布局无关,引用的目标并不一定加载到内存中。在Java中,一个java类将会编译成一个class文件。在编译时,java类并不知道所引用的类的实际地址,因此只能使用符号引用来代替;
2.直接引用:
1)直接指向目标的指针(比如,指向“类型”【Class对象】、类变量、类方法的直接引用可能是指向方法区的指针)
2)相对偏移量(比如,指向实例变量、实例方法的直接引用都是偏移量)
3)一个能间接定位到目标的句柄
1.2.4初始化(initilalization)
对类的静态变量0初始化为指定的值,执行静态代码块
2.类加载器的双亲委派机制
2.1双亲委派机制介绍(先找父亲加载,不行再由儿子自己加载)
1)如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行:
2)如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器:
3)如果父类加载器可以完成类加载任务,就成功返回,子加载器就不会加载,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制。
2.2双亲委派机制的加载流程图
2.3双亲委派机制的作用
解释:
1.防止重复加载同一个.class
。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全.
2.保证核心.class
不能被篡改。通过委托方式,不会去篡改核心.clas
,即使篡改也不会去加载,即使加载也不会是同一个.class
对象了.
3.不同的加载器加载同一个.class
也不是同一个Class
对象。这样保证了Class
执行安全。
2.4打破双亲委派机制
打破双亲委派机制的场景有很多:JDBC、JNDI、Tomcat等,我们以Tomcat为例来说明
2.4.1Tomcat为什么要打破双亲委派机制
Tomcat是个web容器, 那么它要解决什么问题:
2.4.2Tomcat 如果使用默认的双亲委派类加载机制行不行?
不行,1.然而双亲委派机制他的职责就是保证唯一性,那么是无法加载两个相同类库的不同版本的,默认
2.4.3Tomcat的类加载机制