面试题十二:CPU架构适配需要注意哪些问题?
CPU架构适配需要注意哪些问题?
一、面试官视角:这道题想考察什么?
是否有Native开发经验
是否关注过CPU架构适配
是否有过含Native代码的SDK开发的经历(包括如何为他人提供so库)
是否针对CPU架构适配做过包体积优化
涉及包含哪些CPU架构的so库,如果包含得多了话,那么包体积肯定很大,那针对这种情况有没有过类似的优化。
二、题目剖析
1、Native开发才会关注CPU架构
2、不同CPU架构之间的兼容性如何
首先看看CPU架构的指令兼容性,在Android开发过程中,大概能遇到的CPU架构如下所示:
【mips64、mips】、【x86_64、x86】、【arm64-v8a、armeabi-v7a、armeabi】,最常见的CPU架构是【arm64-v8a、armeabi-v7a、armeabi】,最不常见的就是【mips64、mips】,而且这两个CPU架构已经废弃了。
接下来我们看看它们的兼容性如何?
1、mips其实是可以放在mips64机器上跑的,所以mips64兼容mips。
2、x86其实是可以在x86_64机器上跑的,所以x86_64兼容x86。
3、armeabi-v7a其实是可以在arm64-v8a机器上跑的,所以arm64_v8a兼容armeabi-v7a。
4、armeabi其实是可以在x86_64、x86、arm64-v8a、armeabi-v7a机器上跑的,所以x86_64、x86、arm64-v8a、armeabi-v7a兼容armeabi。
综合所述,发现armeabi的兼容性最好!!!
最后举个例子:
项目中的libs目录下有以下so库:armeabi(libmath.so、libui.so)、armeabi-v7a(libmath.so、libui.so)、arm64-v8a(libmath.so、libui.so),那么在arm64-v8a的机器上Native库如何加载呢?
它会优先选择当前CPU对应的CPU架构目录下的so库,也就是会加载arm64-v8a(libmath.so、libui.so)目录下的so库,假设如果arm64-v8a架构的so库里面没有libui.so了,那么会发生什么问题呢?它还是会去arm64-v8a架构的so库里面找,但发现so库里没有libui.so,那么加载就会失败,那刚刚也说了armeabi和armeabi-v7a本身就兼容arm64-v8a,那为什么不去加载它们呢?这是因为CPU加载so库的时候就这么规定的,所以要提供so库就一定要提供一全套,要么就一个都不要提供,这样CPU就会去找它所兼容的so库。
兼容模式运行的一些问题:
1、兼容模式运行的Native库无法获得最优性能(所以x86的电脑上运行arm的虚拟机会很慢!)
2、兼容模式容易出现一些难以排查的内存问题
3、系统优先加载对应架构目录下的so库
3、so库太多如何优化Apk体积
为App提供不同的CPU架构的Native库
实际开发过程中,我们不可能提供所有CPU架构的so库,那就要考虑兼容,兼容性最好的当然就是armeabi了,那是不是我们就只需要提供这一套了呢?如果在性能不敏感且无运行时异常的情况下可以这么干。但目前市场上大部分的机器的CPU架构都已经是armeabi-v7a和arm64-v8a了,所以这个时候提供一套兼容性最好的so库就是armeabi-v7a了,所以我们要结合目标用户群体提供合适的架构。
还有一个方案就是,我们只提供一个CPU架构目录,比如armeabi-v7a,把所需要的so库都扔到这一个目录里面,这样一来里面也可以提供arm64-v8a的so库等,这样的话,我们就可以动态根据当前的CPU架构去选择加载一些特定的so库,微信就是这么干的。
那到底选择那种方案去提供so库呢?
最好的办法就是通过线上监控问题,然后针对性提供Native库。
动态加载Native库
把非启动加载的库放到云端(CSD)上, 然后通过开关让用户选择是否需要加载,需要的话就从云端下发,不需要的话就拉到。
优化so体积
- 默认隐藏所有符号,只公开必要的(-fvisibility=hidden)
- 禁用C++ Exception&RTTI(-fno-exception -fno-rtti)
- 不要使用iostream,应优先使用Android Log
- 使用gc-sections去除无用代码(类似于Java的混淆)
- LOCAL_CFLAGS += -ffunction-sections -fdata-sections
- LOCAL_LDFLAGS += -Wl,–gc-sections
构建时分包(官方提供)
根据CPU架构进行分包,每一个包里面只包含一种CPU架构,然后借助应用市场按CPU架构分发安装包。
1
2
3
4
5
6
7
8splits {
abi {
enable true
reset()
include "armeabi-v7a"、"arm64-v8a"、"x86"、"x86_64"
universalApk true
}
}
4、SDK开发者应当提供哪些so库
- 尽量不在Native层开发,降低问题跟踪维护成本
- 尽量优化Native库的体积,降低开发者的使用成本
- 必须提供完整的CPU架构依赖
三、题目结论
- 注意CPU架构指令兼容关系,以及兼容模式下的问题
- 注意合理提供Native库,在性能与体积上取舍
- 通过代码编写和编译的手段缩减Native库的体积
- 通过动态下发的方式减小安装包的体积
- SDK开发相比App开发者应当多关注的一些问题
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!