这一期我们学习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,这种方法现在还不成熟,有兴趣的朋友可以去了解一下