Android 类加载器机制

类加载机制

概述

  • ClassLoader即类加载,虚拟机将描述类的数据从class字节码文件加载到内存,并对书籍进行 检验、转换解析和初始化,最新形成可以被虚拟机直接使用的Java代码
  • 主要作用:
    • 实现类的加载功能
    • 确保被加载类在虚拟机中的唯一性

ClassLoader加载流程

  • 当需要使用某个类时,JVM虚拟机就会加载它的Class文件,并创建对应的Class对象,将Class文件加载到虚拟机的内存里,这个过程称为类加载
  • 类从被加载到JVM虚拟机内存到被卸载,整个完整的生命周期包括:类加载 --> 验证 --> 准备 --> 解析 --> 初始化 --> 使用 --> 卸载 七个阶段,其中验证、准备、解析这三个部分统称为连接
  • 类加载流程比较复杂,虽然加载过程有复杂的五个步骤,但是除了加载以外,其他四部都是由JVM虚拟机控制的

在这里插入图片描述

  • 步骤一:加载:将外部的Class文件加载到JVM虚拟机内,并存储到方法区
  • 步骤二:验证:确保加载到Class文件里的信息符合JVM虚拟机要求
  • 步骤三:准备:为类变量分配内存,并设置类变量的初始化值(初始值通常为0,非开发者定义的值)
  • 步骤四:解析:将常量池内的符号引用转为直接引用,如hello()方法,hello是符号引用,地址值是直接引用
  • 步骤五:初始化:对类变量进行初始化

双亲委托机制

双亲委托机制即父委托机制,指多个类加载器之间存在父子关系,当一个类加载的过程中,它首先不回去加载,而是委托给父类去加载,父类又委托给父类,因此所有的类加载都会委托给顶层的父类即BoostrapClassLoader进行加载。

如果父类无法完成这个加载请求,子加载器才会尝试自己去加载。

优点

使用双亲委托机制,Java类随着它的类加载器一起具备类一种带优先级的层次关系。通过这种层次关系,可以避免类的重复加载,可以避免核心类被不同的类加载器加载到内存中造成冲突和混乱,保证了Java核心库的安全。

关键类说明

BootstrapClassLoader

  • 启动类加载器
  • 纯C++实现的类加载,没有对应的Java类
  • 主要加载<JAVA_HOME>/lib目录下的核心库

ExtClassLoader

  • 扩展类加载器
  • 类全名是sum.misc.Launcher#ExtClassLoader
  • 主要加载<JAVA_HOME>/lib/ext目录下的扩展类,如swing系列、内置js引擎、xml解析器

AppClassLoader

  • 应用程序类加载器
  • 类全名sum.misc.Launcher$AppClassLoader
  • 负责加载ClassPath所指定类库,开发者可以直接使用该类加载器

在这里插入图片描述

流程图说明

请添加图片描述

流程说明

当有一个Class文件要被加载时,暂时不考虑我们自定义类加载器。最先从AppClassLoader中检查是否加载过(每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了),如果有加载过无需再加载,否则会获取父加载器,再调用父加载器的loadClass()检查是否加载过,同理类似递归调用;直到BootstrapClassLoder检查知否加载过,如果没有加载过则会下沉到子加载器处理。这时候如果子加载器不能加载则抛出ClassNotFoundException异常。

代码分析

双亲委托机制的代码流程在java.lang.ClassLoader#loadClass()

protected Class<?> loadClass(String name, boolean resolve) {
    
    
    Class<?> c = findLoadedClass(name);
    
    //检查类是否被加载过
    if (c == null) {
    
    
        try {
    
    
            //如果没有加载,调用父类的加载器
            if (parent != null) {
    
    
                c = parent.loadClass(name, false);
            } else {
    
    
                //父类加载器为空,使用默认的 启动类加载器
                c = findBootstrapClassOrNull(name);
            }
        } catch (ClassNotFoundException e) {
    
    
        }

        if (c == null) {
    
    
            //父类加载器无法加载,则调用自身的findClass()进行类加载
            c = findClass(name);
        }
    }
    return c;
}

Android中的类加载机制

区别

Java中的ClassLoader可以加载jar文件和Class文件,这一点再Android中不适用,Android加载的是dex文件,所以在需要重新设计ClassLoader相关类。

Androd中的ClassLoader和Java的ClassLoader相似,也分为两种类型,分别是系统ClassLoader和自定义ClassLoader。系统ClassLoader包含:BootClassLoader、PathClassLoader和DexClassLoader。

Android类加载器关键类说明

在这里插入图片描述

BootClassLoader

  • Android系统启动时会使用BootClassLoader来预加载常用类,与Java中的BootstrapClassLoader不同的是,它不是由C/C++代码实现,而是由Java实现
  • BootClassLoader是ClassLoader的一个内部类

PathClassLoader和DexClassLoader在Android8.0之后完全一样

PathClassLoader

  • 继承自BaseDexClassLoader
  • Android系统使用PathClassLoader加载系统类和应用程序的类,从语义上讲:加载内存中已经安装的apk中的dex文件

DexClassLoader

  • 继承自BaseDexClassLoader
  • 从语义上讲:可以加载内存以外的dex/apk/jar文件

流程图说明

请添加图片描述

热修复实现

代码下载

常用命令:

dx --dex --no-strict --ouput <生成的dex文件名> <class文件包名>

例子:
./dx --dex --no-strict --output /Users/limengge/dev/fixed-01.dex /Users/limengge/dev/fixed/

猜你喜欢

转载自blog.csdn.net/qq_14876133/article/details/119536390