JVM虚拟机(HotSpot)
第二章:类加载子系统
作用:类加载子系统负责从文件系统或者网络中加载class文件。
ClassLoader只负责class文件的加载 这个文件是否可以运行则是看ExecutionEngine(执行引擎)决定
一丶 类的加载过程
宏观加载过程
微观加载过程
1.加载:
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的哥哥数据的访问接口
- 通过类的全限定名称获取定义此类的二进制字节流
补充加载class文件的方式:
- 通过本地系统直接加载+
- 通过网络获取,例如:Web Applet
- 从zip压缩包中读取 成为日后jar,war格式的基础
- 运行时计算生成 例如:动态代理
- 由其它文件生成 例如:JSP应用
- 从专门的数据库中提取.class文件(较为罕见)
- 从加密文件中获取,例如:防class文件被反编译的保护措施
2.链接:
验证(Verify):
确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性。
主要包括四种验证:文件格式,元数据,字节码,符号应引用
准备(Perpare)
- 为类的变量分配内存并设置该类变量的默认初始值 ( 零值 )
- 这里不包含 final 修饰的 static (也就是常量),因为 final (常量)在编译的时候就会分配了, 准备阶段会显示初始化
- 这里不会为实例变量分配初始化,类变量会分配在方法中去,而实例变量是会随着对象那个一起分配到Java堆中
解析(Resolve)
解析往往会伴随着JVM在执行完初始化之后再执行
3.初始化:
初始化阶段就是执行类构造器方法< client >() 的过程
< client >() 是不同于累的构造器 (关联 :构造器是虚拟机视角下的是< init >() )
若该类具有父类,JVM会保证子类的< client>()执行前,父类的< client>()已经执行完毕
虚拟机必须保证一个类的< client>() 方法在多线程下被同步加锁
当没有静态变量 和 静态代码快的时候,是不会生成类构造器方法 :< client>()方法 此方法不需要进行定义,是Java编译器自动手机类中的所有类变量的赋值动作和静态代码块中的语句合并而来
二丶类加载器分类
JVM支持俩种类加载器:
1.引导类加载器(Bootstrap ClassLoader)
2.自定义类加载器 (User-defined ClassLoader)Java虚拟机将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器
最常见的三个类加载器始终是这三个:
1.引导类加载器(Bootstrap Class Loader)(C,C++编写)
2.扩展类加载器(Extension Class Loader)(Java编写)
3.系统类加载器(System Class Loader)(Java编写)
补充:
- Java的核心类库都是由引导类加载器加载的。
- 对于用户自定义类来说,使用默认系统类加载器进行加载
引导类加载器 BootStrap ClassLoader
- 这个类是使用 c / c++语言实现的,嵌套在JVM内部。(是获取不到的)
- 用来加载Java的核心类库,用于提供JVM自身需求的类
- 出于安全考虑,BootStrap启动类加载器只能加载包名为Java,javax,sun等开头的类
扩展类加载器 Extendsion ClassLoader
- Java语言编写 ,由sun.misc.Launcher$ExtClassLoader
- 派生于ClassLoader类
- 复类加载器为启动类加载器
- 从Java.ext.dirs系统属性所制定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下家再类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载起加载。
应用程序类加载器(系统类加载器 AppClassLoader)
- Java语言编写 由sun.misc.Launcher$ AppClassLoader实现
- 派生于ClassLoader类
- 父类加载器为扩展类加载器
- 该类加载时程序中默认的类加载器,一般来说,Java应用的类都是由它来完成的。
用户自定义类加载器
为什么要自定义类加载器
- 隔离加载类
- 修改类加载的方式
- 扩展加载源
- 防止源码泄漏
简要实现步骤
5. 继承ClassLoader类
6. 在 JDK1.2之后,不建议覆盖loadClass()方法,而是建议把自定义的类加载逻辑写在findClass()方法中
7. 没有太过复杂的要求,可以直接继承URLClassLoader类,可以避免自己编写findClass()方法。
(扩展) 关于ClassLoader类
他是一个抽象类,其后所有的类加载器都继承自ClassLoader(不包括启动类加载器)。
sun.misc.Launcher他是一个Java虚拟机的入口应用
三丶双亲委派机制
工作原理
1. 如果一个类加载器收到类加载请求,他并不会自己先去加载,而是把这个请求委托给父类的加载器去执行
2. 如果父类加载器还存在其父类加载器,则进一步向上委托,一次递归,请求最终将到达顶层的启动类加载器
3. 如果父类加载器可以完成加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。
依次向上委托,依次向下执行(若父类不能完成)
优点:
- 避免类的重复加载
- 保护程序安全,防止核心API被随意修改
沙箱安全机制:
保护程序受到外界的恶意攻击。
其他:
在JVM中标识俩个class对象是否为同一个类存在的俩个必要条件:
- 类的完整类名必须一致,包括包名
- 加载这个类的ClassLoader (指ClassLoader实例对象) 必须相同
JVM必须知道一个类型是有启动类加载器加载还是由用户类加载器加载,如果一个类型是由用户类加载器加载的,那么JVM会讲这些个类加载器的一个引用作为类型信息的一部分保存在方法区中(也就是说如果不是启动类加载器就会进行保存)。当解析一个类型到另一个类型到另一个类型的引用的时候,JVM需要保证这俩个类型的类加载起是相同的。
主动使用
- 创建类的实例
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射(Class.forName(“com.atccdx.Test”))
- 初始化一个字累
- Java虚拟机启动时被标明为启动类的类
- JDK7 开始提供的动态语言支持
Java类的方式都被看作是对类的被动使用,都不会导致累的初始化。