深入理解类加载器和动态加载二者之间的关系和原理

类加载器

JVM的双亲委派

双亲委派模型

从 Java 虚拟机角度讲,只存在两种类加载器:
一种是启动类加载器(C++ 实现,是虚拟机的一部分);
另一种是其他所有类的加载器(Java 实现,独立于虚拟机外部且全继承自 java.lang.ClassLoader)

启动类加载器
加载 lib 下或被 -Xbootclasspath 路径下的类

扩展类加载器
加载 lib/ext 或者被 java.ext.dirs 系统变量所指定的路径下的类

引用程序类加载器
ClassLoader负责,加载用户路径上所指定的类库。

img

除顶层启动类加载器之外,其他都有自己的父类加载器

工作过程:如果一个类加载器收到一个类加载的请求,它首先不会自己加载,而是把这个请求委派给父类加载器。只有父类无法完成时子类才会尝试加载。

具体代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
//1.先检查是否已经加载过--findLoaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
//2.如果自己没加载过,存在父类,则委托父类
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}

if (c == null) {
//3.如果父类也没加载过,则尝试本级classLoader加载
c = findClass(name);
}
}
return c;
}

代码解释:
1)先检查自己是否已经加载过class文件,用findLoadedClass方法,如果已经加载了直接返回
(2)如果自己没有加载过,存在父类,则委派父类去加载,用parent.loadClass(name,false)方法,此时会向上传递,然后去父加载器中循环第1步,一直到顶级ClassLoader
(3) 如果父类没有加载,则尝试本级classLoader加载,如果加载失败了就会向下传递,交给调用方式实现.class文件的加载

作用

(1) 防止同一个.class文件重复加载
(2) 对于任意一个类确保在虚拟机中的唯一性,由加载它的类加载器和这个类的全类名一同确立其在Java虚拟机中的唯一性
(3) 保证.class文件不被篡改,通过委派方式可以保证系统类的加载逻辑不被篡改

Android中类加载机制

image-20211010143826461

进入JAVA层后,

Zygote总结:
1)解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()方法

2)调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数

3)通过JNI方式调用ZygoteInit.main(),第一次进入Java世界

4)registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求

5)preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率

6)通过startSystemServer(),fork得力帮手system_server进程,也是Java Framework的运行载体(下面讲到system server再详细讲解)

7)调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作

Android的类加载机制和JVM一样遵循双亲委派模式,在dalvik/art启动时将所有Java基本类和Android系统框架的基本类加载进来,预加载的类记录在/frameworks/base/config/preloaded-classes

Android类加载器层级关系及分析

image-20211010145342789

1
2
3
4
5
Android中的ClassLoader类型分为系统ClassLoader和自定义ClassLoader。其中系统ClassLoader包括3种是BootClassLoader、DexClassLoader、PathClassLoader
(1)BootClassLoader:Android平台上所有Android系统启动时会使用BootClassLoader来预加载常用的类
(2)BaseDexClassLoader:实际应用层类文件的加载,而真正的加载委托给pathList来完成
(3)DexClassLoader:可以加载dex文件以及包含dex的压缩文件(apk,dex,jar,``zip``),可以安装一个未安装的apk文件,一般为自定义类加载器
(4)PathClassLoader:可以加载系统类和应用程序的类,通常用来加载已安装的apk的dex文件
1
2
3
补充:
Android 提供的原生加载器叫做基础类加载器,
包括:BootClassLoader,PathClassLoader,DexClassLoader,InMemoryDexClassLoader(Android 8.0引入),DelegateLastClassLoader(Android 8.1引入)

无论是系统类加载器(PathClassLoader)还是自定义的类加载器(DexClassLoader),最顶层的祖先加载器默认是 BootClassLoader,与 JVM 一样,保证了基本类的类型安全

类加载时机:

1.隐式加载:
(1)创建类的实例,也就是new一个对象
(2)访问某个类或接口的静态变量,或者对该静态变量赋值
(3)调用类的静态方法
(4)反射Class.forName("android.app.ActivityThread")
(5)初始化一个类的子类(会首先初始化子类的父类)

2.显示加载:
(1)使用LoadClass()加载
(2)使用forName()加载

中间是一些更底层的代码和分别做了什么事,我没看那么仔细,大概了解了一下,也就懒得整理

Android类加载详细流程:

image-20211010150449575

实验

参考

Java虚拟机(JVM)你只要看这一篇就够了!

Android加壳与脱壳(1)——深入理解类加载器和动态加载

Android核心组成部分之Dalvik虚拟机简单介绍

[Dalvik虚拟机的启动过程分析](