贝壳找房 iOS 冷启动优化实践

如果无法正常显示,请先停止浏览器的去广告插件。
分享至:
1. ⻉壳找房 iOS 冷启动优化实践 陈旭 ⻉壳找房 资深工程师
2.
3. 优化效果展示
4. 1. 启动优化常⻅误区 目 录 CONTENTS 2. 优化思路分析 3. 主要优化方案及实践 4. 规范与监控 5. 总结与展望
5. 启动优化常⻅误区
6. 冷启动测试标准 01 重启手机,并静置 2-3 分钟, 或杀进程后静置 10 分钟以上 03 关闭 iCloud 或者保持使用同一 个 iCloud 账户 02 打开⻜行模式或者 mock 网络环境 04 使用 release 版本
7. 冷启动优化的本质 首要目标是只做必要的事、不做重复计算 只做现在必须做的事,不过早优化 资源换时间(空间换时间、时间换时间) 算法、策略等内部优化 充分利用 CPU 多核性能,最短时间执行完毕
8. 冷启动优化的常⻅误区 耗时操作简单放到子线程就可以了 任务延迟执行固定时间 任务延后到首页显示之后就完成目标了 启动阶段 CPU 占用过高会有问题
9. 优化思路分析
10. iOS冷启动阶段划分 • System Interface : 加载主二进制、启动 dyld、加载动态库以及 libSystem 初始化 • Runtime Init : 执行 +load 和 static initializer 初始化函数等 • 其他:实例化 UIApplication 和 UIApplicationDelegate、处理生命周期回调、首帧 渲染直到首⻚渲染完成
11. 优化可行性分析 System Interface Application Init Runtime Init • 减少或延迟各种 SDK 的初始化 • 避免在+load 里操 作、延迟加载+load 及减少 static initializer 等 • 避免链接不使用的框 架 • 减少动态库的加载 • 减少 OC 类 • 分类的个数等 Initial Frame Render Extended • 减少视图层级和视图数量 • 懒加载 View • 变 AutoLayout 为手动 frame 布局等 • 去掉 viewDidLoad 和 viewWillAppear 中不必 要的逻辑,少做事不做事
12. ⻉壳 iOS 冷启动阶段划分 优化前 优化后
13. 优化成果 • 以 B 端核心 App Link 为例,该 App 集成了二手、新房、租赁、 装修、直播、培训、IM 、VR 、IoT 等十几个业务 • 数百万行代码,近 200 个组件,Native ⻚面超过 500 个, Flutter ⻚面超过 350 个,H5 ⻚面超过 900 个,业务和功能多, 复杂度高,优化难度极高 收益 u 优化了启动速度,提升了经纪 人的工作效率和体验 u 实现了生命周期的解耦,减少 了沟通成本和对平台的打扰 u 沉淀了通用的冷启动优化的技 术项,方便推广到其他 App u 成果可以持续得到巩固,从机 制上避免了业务方对冷启动的 干扰
14. 主要优化方案
15. 思路 • 大的指导方针是延迟、内部优化、懒加载、异步等 • 以最小集为例,谁都觉得自己重要,但哪些是启动过程中真正不可缺少的,值得我们 思考 • 按最小集进行延迟,非最小集的任务项全部延迟,如何低成本且保持⻓效机制 • 启动快了,还要保证首⻚渲染完成后不会卡顿 • 针对各个技术点以及各个任务项需要进行内部优化
16. ⻉壳 B 端 App 架构
17. 主要方案 优化包括两部分,main()函数之前和 main()函数之后,简称 Premain 和 Postmain 。 Postmain Premain 动态库懒加载 • • • • 如何实现 如何手动加载 何时加载 注意事项 编译期消除 I/O Static Initializer • 如何配置 • 如何实现 • • • • 背景 扫描 分发 修改 无用代码删除 框架优化 • 最小集 • 静态扫描 • 动态覆盖率检查 • 生命周期延迟 • 启动器和任务 • 0PV 检测 编排 首⻚渲染优化 • 资源预加载 • 数据预加载 • 布局预加载
18. 1.1 最小集 根据⻉壳 App 的现状梳理出的最小集 • Crash 监控必须最早 • 网络配置不可或缺 • attach window、底部 tabbar 、首⻚展示与 UI 显示相关 • 日志、埋点等看耗时评 估,可以在启动阶段缓 存,启动完再写入
19. 1.2 框架优化-生命周期延迟 任务 本身 任务 调度 耗时 线程 切换 并发对 不⻬ 任务项 延迟到 首页渲 染完成 之后 前期思路: 转换思路: 一项一项往后挪 把除了最小集之外 的任务项打包延迟 由于任务项之间 的依赖,要延迟 就要做到解耦, 效率非常低 冷启动加快,打 散延迟的任务 项,按照封装过 的生命周期进行 填空
20. 1.2 框架优化-生命周期延迟
21. 1.3 启动器
22. 1.4 任务编排
23. 1.5 线程管理 iOS 的 GCD 管理线程很方便,但为了进行统一的管控,我们根据优先级和分 类创建了 3 个线程队列: 主线程队列 管控所有UI操作及 必须在主线程执行 的高优和低优任务 后台线程队列 管控可以并行执行 的任务项 闲时线程队列 管控可以闲时执行的 任务
24. 2. 首⻚渲染优化 02 首页、底部tab的图片等可以提前预加载, 01 首页没有使用 Flutter [UIImage imageNamed:] 04 拆细粒度,微小变化时局部刷新,不 03 要全局刷新 首页数据缓存提前加 载、首页布局预加载 05 减少页面层级,不需要显示的 view 进行懒加载
25. 3. 动态库懒加载 如何查看app里的动态库 otool -L /Users/chenxu/Desktop/XXX.app/XXX 动态库优点 • • • 资源隔离支持重命名 可按需加载 提高本地编译速度等 动态库懒加载 只打包进app, 不参与链接,业 务调用的时候手动加载 动态库缺点 • 影响启动性能
26. 3. 动态库懒加载 配置 podspec里添加spec.weak_frameworks = 'XXX' 运行时手动加载 保证Link Binary With Libraries 和 Other Linker Flags 没有链接对应的动态库。 方式一 方式二 使用-[NSBundle loadAndReturnError:] , 优点是可以访问资源 直接使用dlopen()
27. 3. 动态库懒加载 调用时机 业务之间通过 Router 调用,把逻辑集 中到 Router 内,调用的时候懒加载 哪些动态库适合懒加载 依赖少的业务 bundle 注意事项 n 需要在 Other Linker Flags 里添加 - undefined dynamic_lookup 指令 n Strip Style 设置为 Non-Global Symbol n 动态库符号缺失检查,nm –um 命令 获取动态库依赖的外部符号, nm – gm 获取 APP 依赖的所有符号, 前者 不在后者中,则说明缺失
28. 4. 编译期消除I/O 1. 选中 target , 在 Build Phases 中点+号创建新的 New Run Script Phase,添 加脚本 2. 编译期脚本读取 plist 生成 python 的字典和数组,并转 为 OC 字典和数组字面量 3.字符串拼接,生成读取 plist 到内存的方法
29. 5. static initializer治理 背景 扫描原理 C++ 全局常量必须保证在 main 函数之前初始化完毕,从而增加耗时 mod_init_func 的运行时机晚于 +load,可以在运行时 hook 分发 通过遍历 linkmap 中的 Symbols 能找到扫描的符号所属的文件号,而对应文件 号在 Object files 是能找到所属组件和文件名,进而能找到对应负责人 治理 __attribute((constructor)) 和 C++ 全局常量懒加载
30. 6. 无用代码删除 0 PV扫描 静态分析 1. __objc_class_list & __objc_class_refs 做差集 1. hook VC 的生命周期,线上统 2. AppCode IDE 进行扫描 2. 统计本地 native ⻚面总和 计运行中的 VC 3. 0 PV ⻚面 = 总⻚面 - 浏览了 的⻚面 动态覆盖率检查 OC 的类首次初始化时, +initialize 会被执行,系统会自 动标记
31. 7. 其他优化项 1 避免 router 调用,首⻚之前的 router 调用改为手动调用 2 首⻚使用真实的 VC,其他都是空 VC,等首⻚渲染完成,再把首⻚外的 VC 替换掉 3 手动调用homeVC.view来触发首⻚VC的viewDidLoad 4 synchronized(self) 实现单例的做法改为无锁的 dispatch_once , 防止并发访 问锁可能引起的耗时 5 避免直接 I/O 的方式读取 info.plist ,系统已经提供了内存读取的 API
32. 优化难点 1 2 4 启动任务项做延 +load C++ 动态库懒加载效果 每个研发人员的水 迟、异步可能会打 initializer ,涉及业 明显,但是改造成 平也参差不⻬,无 乱时序,有潜在的 务线众多,需要持 本较高,还需要注 意间可能就影响到 ⻛险,需要对业务 续协调、推动和跟 意业务⻛险 冷启动优化,管控 做详细的梳理和⻛ 踪 险的评估 、 3 困难
33. 规范与监控
34. 规范 新增或修改任务要 首页渲染完成前不 不允许新增 +load 有足够的理由,必 允许监听系统生命 耗时方法 须经过严格的 周期 Code Review 不允许新增 C++ 新增动态库必须经 任务项相对上个版本 initializer 过评估 有 5ms 以上的增长 时,必须进行修改
35. 监控 线下 线上 建立标准,严格准入 开发 测试 线上 严控新增耗时 及时排查问题 及时预警和 快速定位
36. 总 结 与 展 望
37. 总结 深入优化方案 低成本高收益方案 01 生命周期延迟 02 +load 治理 03 动态库下线 04 二进制重排 05 首⻚预加载 20% 5% 01 动态库懒加载 02 static initializer 治理 03 编译期写入 I/O 1% 04 任务编排 1% 5% 4% 3% 3% 2% ⻉壳app里每个方案对启动速度的提升
38. 展望-自动归因 数据整理 • 每个版本的启动数据聚合、归一化 • 细化每个阶段的时间和每个任务项的时间 数据对比 • 不同版本的数据做diff • 多维度收集启动之前的日志 自动归因 • 增量数据进行智能分析和归因
39. 展望-智能决策
40. Q&A
41.
42. 贝壳找房iOS冷启动优化实践 扫描二维码 提交议题反馈

Accueil - Wiki
Copyright © 2011-2024 iteam. Current version is 2.137.1. UTC+08:00, 2024-11-17 02:28
浙ICP备14020137号-1 $Carte des visiteurs$