当前位置:   article > 正文

Android类加载机制

android类加载机制

概念

JAVA程序被编译器编译之后称为字节码文件(.class文件),当程序需要某个类时,虚拟机便会将对应的class文件进行加载,通过classLoader类加载器加载到虚拟机内存的过程,就是类加载。

类加载作用

  • 实现类的加载功能
  • 确保被加载类在虚拟机中的唯一性

熟悉类加载机制流程之前,先熟悉下Android运行流程,以及dex生成的原因。

Android运行流程

  • Android编译的时候,会将.java文件编译成.class文件
  • 生成apk时,会将.class文件打包成.dex文件
  • Android程序运行的时候,Android的Dalvik/art虚拟机就加载dex文件,然后加载其中的.class文件到内存中来使用。

dex分包方案

原因:

  1. DVM指令集的方法调用指令invoke-kind 索引为16bits,所以最多能引用65535个方法。
  2. DVM中的LinearAlloc是一个固定的缓存区,当方法数超出了缓存区的大小时会报错。

为了解决方法数65536的限制和LinearAlloc的限制从而生成了dex打包方案,打包时将代码分成多个dex,将应用启动时必须用到的类和和这些类的直接引用放到主dex中,其他代码放到次dex中,当应用启动时先加载主dex,待到应用启动后再动态的加载次dex。

类加载流程

类从被加载到JVM虚拟机内存到被卸载,整个完整的生命周期包括:类加载 --> 验证 --> 准备 --> 解析 --> 初始化 --> 使用 --> 卸载 七个阶段,其中验证、准备、解析这三个部分统称为连接。

注:类加载流程比较复杂,虽然加载过程有复杂的五个步骤,但是除了加载以外,其他四部都是由JVM虚拟机控制的
在这里插入图片描述
注意:初始化不会马上执行,当一个类被主动使用的时候才会去初始化,主要有几种情况:

1)当创建某个类的新实例时(如通过new或者反射等);

2)当调用某个类的静态方法时;

3)当使用某个类或接口的静态字段时;

4)当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的方法时;

5)当初始化某个子类时;

Android中的类加载器

类加载进内存后,Android程序通过ClassLoader类去加载内存中的类,然后进行解析运行。
在这里插入图片描述

Android中包含以下几种类加载器:

  1. BootClassLoader :用来加载Framework层的字节码文件。只能加载Android系统的类,是ClassLoader的内部类,开发者无法调用。Android系统启动时会使用BootClassLoader来预加载常用类。
  2. BaseDexClassLoader :是PathClassaLoader和DexClassLoader父类。
  3. PathClassLoader :用来加载内存中已经安装的apk中的dex文件。通常用于加载APK中开发者自己写的类(含三方库)。
  4. DexClassLoader :用来加载指定目录中的字节码文件,可以加载内存以外的aar/apk/jar文件。通常用于执行动态加载,能够加载指定路径的apk/jar/zip/dex文件, 因此很多热修复和插件化方案都采用。(DexClassLoader可以指定odex的路径,而PathClassLoader则采用系统默认的缓存路径,在8.0以后没有区别)
  5. URLClassLoader:加载.jar文件和文件夹中的class,javaWeb等使用,谷歌不用。

BaseDexClassLoader为核心类。常用的ClassLoade就两个:DexClassLoader 和 PathClassLoader。

ClassLoader类加载流程

  1. 加载一个类是通过双亲委托机制来实现的
  2. 第一次加载class,是通过BaseDexClassLoader中的findClass方法实现的;接着进入DexPathList中的findClass方法,内部通过遍历Element数组,从Element对象中去查找类;Element实际上是对Dex文件的包装,最终还是从dexfile去查找的class
  3. 一般app运行主要用到2个类加载器,一个是PathClassLoader:主要用于加载自己写的类;另一个是BootClassLoader:用于加载Framework中的类
  4. 热修复和插件化一般是利用DexClassLoader来实现
  5. PathClassLoader和DexClassLoader其实都可以加载apk/jar/dex,区别是DexClassLoader可以指定optimizedDirectory,而PathClassLoader只能使用系统默认位置。但是在8.0 以后二者是没有区别的,只能使用系统默认的位置

以下为关联到的知识点:

双亲委派机制

当加载一个类时,会优先使用父类加载器加载,当父类加载器无法加载时才会使用子类加载器去加载。这么做的目的是为了避免类的重复加载

类的加载过程,Person person = new Person();为例进行说明

  1. 因为new用到了Person.class,所以会先找到Person.class文件,并加载到内存中
  2. 执行该类中的static代码块,如果有的话,给Person.class类进行初始化
  3. 在堆内存中开辟空间分配内存地址
  4. 在堆内存中建立对象的特有属性,并进行默认初始化
  5. 对属性进行显示初始化
  6. 对对象进行构造代码块初始化
  7. 对对象进行与之对应的构造函数进行初始化
  8. 将内存地址付给栈内存中的p变量

参考链接

  1. Android类加载器机制
  2. Android类加载机制
  3. Android热修复:底层替换类加载原理总结 及 DexClassLoader类加载机制源码探索
  4. Java类加载机制笔记
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/247744
推荐阅读
相关标签
  

闽ICP备14008679号