这一期我们学习
Zygote
在启动过程中的预加载分析与优化
下面我们来看一下我们
preload
加载资源的一个过程
我们加载资源分为三种,第一个就是preloadClasses
预加载我们的系统类,这个系统类定义的文件是在
frameworks/base/preloaded-classes
,我们加载的一个过程其实是
Class.forName
来真正的加载这个类,加载完之后我们就会在
zygote
中查找到这个类,这就是预加载的一个过程;第二个是我们要预加载一些资源,这个资源分为两种,第一个是我们的图片,第二个是我们一个颜色的设置,我们所说的图片以及颜色设置,它定义在我们的
frameworks/base/core/res/res/values/arrays.xml
中,当他编译生成
jar
包时,我们会把一些图片资源,以及一些颜色的定义全部生成相关的
xml
,然后我们可以在
zygote
启动的时候,使用
preloadResource()
把这些资源提前加载进来,在加载的过程中,我们会把它保存在一个全局变量中;第三个预加载就是加载我们的
OPengl
资源
下面我们来看一下我们预加载资源的目的是什么
首先我们知道我们的每一个APP
都是我们的
zygote
创建的,如果我们的
zygote
提前把我们所需要的一些系统的类,和
resource
全部加载完之后,当我们使用
fork
这个系统调用去创建一个子进程的时候,我们的子进程就会把这个系统资源,以及系统类全部继承过来,然后我们在调用
java
的方法再去启动我们的应用,这是我们就会发现我们新的应用已经把这两个资源给继承过来了,这样的话我们的应用就不会去重新加载我们的资源和我们的类了,这样我们就能提高应用的启动和运行速度,为什么说提高应用的启动和运行速度呢,说可以提高启动速度是因为,我们在启动一个应用的时候,不需要再去加载这些资源,这样就可以提高应用的启动速度了,因为我们加载这个资源和类,这个耗时是几秒钟的事,如果我们省去这一个步骤,不做预加载,那么启动应用的时候,它就会自己去找这些资源和类,如果在运行过程中再去找这些资源和类,那么他的运行速度肯定就会受到影响,这些资源是所有应用都需要的,所以说在
zygote
启动时把这些资源和类与加载进来,能提高应用的启动和运行速度
下面我们再来看一下
preloadClasses
他的一个过程
preloadClasses
其实就是导入我们类的一个配置文件,这个配置文件在我们的
frameworks/base
下面定义好了,他有我们系统里边的每一个类,然后把这个文件打开,然后把他读出来,在使用
Class.forName
把这些类加载到
zygote
中。
下面我们看一下他的具体实现过程,打开
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
这个文件,查找到
preloadClasses
这个方法
首先他会打开我们这个资源文件,这个资源文件的定义是在
frameworks/base/preloaded-classes
里边,我们可以打开它看一下,可以看到它里边使我们
Android
下的所有的类,这个
preloadClasses
所做的事情就是,把这些类提前加载进来。它加载的过程首先就是打开这个文件,然后把这个文件一条条的读进来,如果看到一个
#
号,那么说明这一行是不需要
load
的,如果不是
#
号,那么就会调用
Class.forName
把他加载进来,直到加载完成。在最后我们会打印一下加载时间,和加载了多少类,这个就是
preloadClasses
的一个过程
下面我们来看一下是如何加载我们系统资源的
我们加载系统资源分为两部分,第一是加载资源,第二是加载颜色的一些设置,首先调用的是preloadResource()
来加载系统资源,加载时我们会首先创建一个
resource
,然后把它赋值给我们的全局变量,
mResource
,他用来保存我们系统的资源,加载资源时首先是
preloadDrawables()
,就是把刚才看到的所有的
xml
的所有文件给
load
进来,第二个就是加载一些颜色的设置,这个也在我们的
xml
中,我们来看一下代码的具体实现
他所的就是把我们com.android.internal.R.array.preloaded_drawables
给他
load
进来,我们来看一下这个文件,这个文件是在
frameworks/base/core/res/res/values/arrays.xml
中,打开它可以看到,这里面是一些图片文件,然后会把它预加载到这个
mResource
中,
preloaded_drawables
所做的事情就是,把我们的图片资源使用
mResources.getDrawable
的方法把它加载进来,这就是我们加载资源的一个过程,然后会将我们加载资源的个数给显示出来,再加载我们预先设置好的颜色,加载颜色的过程也是一样的,它是用
mResources.getColourStateList
的方法,加载到我们的
mResources
中,这样就完成了图片和颜色的预加载
我们用
adb
来看一下我们预加载这些资源用的时间
我们可以看到总的时间大概是4
秒多,这个时间是在我们
Android
启动过程中所要花费的时间,所以
Android
手机启动慢就有这个方面的原因
下面我们来看一下如何利用我们的硬件资源来加快我们
load
的一个效率,我们可以看到,我们加载类的时间基本大于
2
秒,加载
Resource
的时间基本大于
1
秒,这时我们可以考虑采用多线程的方式去加载我们的类,和
Resource
,我们可以使用线程池的方法实现这个多线程加载
我们加载的过程首先是,在zygote
中创建一个线程池,这个线程池去实现一个类和资源的加载,当我们执行
preloadClass
时,将加载类的操作串行添加到线程池中,添加完之后我们去解析我们的
resource
,然后将我们
resource
中加载的资源操作串行的添加到我们的线程池中,然后就会等待线程池工作结束,当他工作完成之后,我们就可以知道,我们加载资源和类的一个过程已经完成了,完成之后就可以去做其他的操作了,如果说线程池的个数是
4
个,并且
CPU
也是
4
核的话,那么他的执行效率肯定比我们使用一个线程快很多,这就是用多线程的方法优化
zygote
的一个启动过程
下面我们来看一下我们使用多线程或者线程池优化的一个前提
我们使用多线程优化的实质是:使我们的
zygote
进程最大限度的抢占
CPU
,所以说我们的执行才能更快一些。
除了使用多线程优化之外呢,还有另一种方法,就是
BLCR
,这种方法现在还不成熟,有兴趣的朋友可以去了解一下