抖音字体大小设置方法安卓 抖音字体大小设置方法(13)


抖音字体大小设置方法安卓 抖音字体大小设置方法


可以看到当 PathClassLoader 到 BootClassLoader 的 ClassLoadeer 链路上只有 PathClassLoader 时,java 层的 findLoadedClass 方法调用后,并不止如其字面含义的去已加载的类中查找,其还会在 native 层直接通过 DexFile 去加载类,这种方式相对于回到 java 层调用 findClass 再调回 native 层通过 DexFile 加载可以减少一次不必要的 jni 调用,在运行效率上是更高的,这是 art 虚拟机对类加载效率的一个优化 。
抖音中 ClassLoader 模型
在前面我们介绍了 Android 中的类加载相关机制,那么我们究竟在类加载方面做了哪些优化,要解答这个问题我们需要了解一下抖音中的ClassLoader 模型 。在抖音中为了减少包体积,一些非核心功能我们通过插件化的方式进行了动态下发 。在接入插件化框架后抖音中的 ClassLoader 模型如下:
除了原有的 BootClassLoader 和 PathClassLoader 另外引入了 DelegateClassLoader 和 PluginClasLoader;DelegateClassloader 全局 1 个,它是 PathClassLoader 的 parent,它的 parent 为 BootClassLoader;PluginClassLoader 每个插件一个,它的 parent 为 BootClassLoader;DelegateClassLoader 会持有 PluginClassLoader 的引用,PluginClassLoader 则会持有 PathClasloader 的引用;
抖音字体大小设置方法安卓 抖音字体大小设置方法


这种 ClassLoader 模型有一个非常明显的优点,那就是它能够非常方便的同时支持类的隔离、复用以及插件化与组件化的切换;
类的隔离:如果在宿主和多个插件中存在同名类,在宿主中使用某个类则会首先从宿主 apk 加载,在插件中使用某个类,则会优先从当前插件的 apk 中加载,这种加载机制单 ClassLoader 模型的插件框架是无法支持的;类的复用:在宿主中使用某个插件中特有的类时,我们可以在 DelegateClassLoader 中检测到类加载失败,进而使用 PluginClassLoader 去插件中加载,实现宿主复用插件中的类;在插件中使用某个宿主特有的类时,可以在 PluginClassLoader 中检测到类加载失败,进而使用 PathClassLoader 去进行加载,实现插件复用宿主中的类,这种复用机制其他多 ClassLoader 模型的插件框是无法支持的;插件化与组件化自由切换:这种 ClassLoader 模型下,我们加载宿主/插件中的类时无需任何显示的 ClassLoader 的指定,我们可以很方便的在直接依赖的组件化方式以及 compileonly+插件化的方式之间切换;
ART 类加载优化机制被破坏
上面介绍了抖音的 ClassLoader 模型的优点,但是其也有一个比较隐蔽的不足,那就是它会破坏 ART 虚拟机对类加载的优化机制 。
通过前面的介绍我们了解,当 PathClassLoader 到 BootClassLoader 的 ClassLoader 链路上只有 PathClassLoader 时,则可以在 native 层进行类的加载,以减少一次 jni 的调用 。在抖音的 ClassLoader 模型中,PathClassLoader 与 BootClassLoader 之间存在一个 DelegateClassLoader,它的存在会导致“PathClassloader 到 BootClassLoader 的 ClassLoader 链路上只有 PathClassLoader”这一条件被破坏,这导致我们 app 中所有类的首次加载都需要多一次 jni 的调用 。一般情况下多一次 jni 的调用不会带来多少消耗,但是对于启动阶段大量类加载的场景,这个影响也是比较大的,会对我们的启动速度造成一定的影响 。
非侵入式优化方案:延迟注入
了解插件化对类加载造成负向的原因,优化思路也就比较清晰了——将 DelegateClassLoader 从 PathCLasLoader 和 BootClassLoader 之间移除掉 。
通过前面的分析,我们知道引入 DelegateClassLoader 是为了在使用 PathClassLoader loadClass 失败时,可以使用 PluginClassloader 去插件中加载,因此对于不使用插件的场景,DelegateClassloader 是完全没有必要的,我们完全可以在需要用到插件功能时再进行 DelegateClassloader 的注入 。

推荐阅读