Java面试进阶:类加载和双亲委派模型

类加载过程:

加载、链接、初始化

加载阶段(Loading),它是 Java 将字节码数据从不同的数据源读取到 JVM 中,并映射为 JVM 认可的数据结构(Class 对象)

链接(Linking),这是核心的步骤,

      验证(Verification),这是虚拟机安全的重要保障,JVM 需要核验字节信息是符合 Java 虚拟机规范的

      准备(Preparation),创建类或接口中的静态变量,并初始化静态变量的初始值。但这里的“初始化”和下面的显式初始化阶段                                               是有区别的,侧重点在于分配所需要的内存空间,不会去执行更进一步的 JVM 指令。

      解析(Resolution),在这一步会将常量池中的符号引用(symbolic reference)替换为直接引用

初始化阶段(initialization),这一步真正去执行类初始化的代码逻辑,包括静态字段赋值的动作,以及执行类定义中的静态初始化块内的逻辑

普通原始类型静态变量和引用类型(即使是常量),是需要额外调用 putstatic 等 JVM 指令的,这些是在显式初始化阶段执行,而不是准备阶段调用;而原始类型常量,则不需要这样的步骤。

双亲委派模型:

三个特征:

不是所有类加载都遵守这个模型比,如 JDK 内部的 ServiceProvider/ServiceLoader机制,用户可以在标准 API 框架上,提供自己的实现,JDK 也需要提供些默认的参考实现。 如Java 中 JNDI、JDBC、文件系统、Cipher 等很多方面,都是利用的这种机制,这种情况就不会用双亲委派模型去加载,而是利用所谓的上下文加载器。

可见性,子类加载器可以访问父加载器加载的类型,但是反过来是不允许的

单一性,父加载器中加载过的类型,子加载器中不会重复加载。类加载器“邻居”间,同一类型仍然可以被加载多次,因为互相并不可见。

JDK 9看,Jigsaw 项目引入了 Java 平台模块化系统(JPMS)类加载器,类文件容器等都发生了非常大的变化:

扩展类加载器被重命名为平台类加载器,扩展的文件放入 classpath 里;rt.jar 和 tools.jar 同样是被移除了;增加了 Layer 的抽象, JVM 启动默认创建 BootLayer,开发者也可以自己去定义和实例化 Layer,可以更加方便的实现类似容器一般的逻辑抽象。

 

自定义类加载器:

需求场景:两个模块依赖于某个类库的不同版本,如果分别被不同的容器加载,就可以互不干扰。应用需要从不同的数据源获取类定义信息。或者是需要自己操纵字节码,动态修改或者生成类型(平台化项目中有相关实现)。

过程:可参考(https://www.baeldung.com/java-classloaders

1)通过指定名称,找到其二进制实现,在特定数据源根据名字获取字节码,或者修改或生成字节码。

2)然后,创建 Class 对象,并完成类加载过程。

 

如何提高加载效率:

1)AOT,相当于直接编译成机器码

2)AppCDS:JVM 将类信息加载, 解析成为元数据,将这些元数据直接存储在文件系统中,通过内存映射技术,直接映射到相应的地址空间,免除了类加载、解析等各种开销。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章