日活超过 3 亿的快手是怎么进行性能优化的?( 二 )


内存镜像转储,我们研发了一种高效 dump 方案,解决了传统方法虚拟机内存转储需要暂停虚拟机的问题 。内存镜像分析,研发了基于 shark 的低内存开销、低 CPU 开销的独立进程解析方案,采用了更为节省内存的高性能数据结构以及更为高效的内存索引,增加了同类型对象阈值用于 GC Root 最短路径搜索剪枝,可以在手机侧 10 分钟内完成 400M 镜像、200 万 对象的极端 case 解析 。内存镜像裁剪,我们研发了一种 hook 虚拟机内存镜像转储时 IO 的高效裁剪方案,解决了传统裁剪效率低、成功率低的问题,辅以 zstd 压缩,90% 内存镜像可以压缩至 80M 内 。

日活超过 3 亿的快手是怎么进行性能优化的?

文章插图
 
C 的内存 我们主要利用编译器插桩及 malloc hook 记录所有活着的内存块,利用 mark-and-sweep 算法在单独的进程中分析测试应用进程 Native Heap 中不可达的内存块 。将发现的不可达内存上报后台 。具体操作如下:
利用编译器插桩及 malloc hook 记录所有活着的内存块(包含内存块地址、backtrace 信息),对性能影响较小 。利用 mark-and-sweep 算法在单独的进程中分析测试应用进程 Native Heap 中不可达的内存块(包含内存块地址) 。对于步骤 2 中收集到的不可达内存块,从 1 中获取其对应的 backtrace 信息,将泄漏信息上报至 APM 监控平台 。APM 监控平台解析泄漏信息(backtrace 信息符号化等),做友好的展示,业务方根据 APM 展示信息可快速定位泄漏问题 。
InfoQ:如何优化卡顿?
杨凯: 我们定义的卡顿是:一个消息 / 任务在主线程执行超过 1s 。
优化主要看卡顿的堆栈特征、当前 CPU 占用、其它线程正在执行的任务 。通常有以下几种情况:CPU 占用过高(一般是主线程或者子线程任务重),主线程等锁(需要看其它线程当时的任务),系统服务忙(binder 调用耗时长) 。解决方案一般需要结合场景、页面,增加 log 等,丰富更多上报信息,定位主要问题,或者缓解 CPU 占用 。
InfoQ:在启动优化这部分做了哪些动作,优化前后对比效果如何?
杨凯: 启动优化我们主要是建立启动框架,将启动所有的任务,全部收敛到框架内,统计每个任务的耗时、相互依赖关系 。
启动优化定位问题:
将启动时运行的代码,按照功能,做成 task;线上收集每个 task 的耗时;在线下,在 Android 端利用 systrace、在 IOS 端利用自研的火焰图工具,来分析耗时 。
优化手段:
优化整体流程;分场景、分用户特性,推迟甚至取消一些 task (根据用户登录状态,用户使用习惯,后面我们会用机器学习预测 task 是否需要初始化);特别关注一些锁的等待、主线程 CPU 分配不足等问题;一些系统 API,背后会引发一系列的初始化(setcookie,会引起 WebView 内核初始化);主动 dex2oat;二进制重排、dex 重排 。

日活超过 3 亿的快手是怎么进行性能优化的?

文章插图
 
【日活超过 3 亿的快手是怎么进行性能优化的?】另外,针对线上收集到的信息,重点优化耗时较多的任务 。线下通过 systrace 等工具,定位、验证修复 。然后依据用户的不同特征,初始化不同任务 。例如,未登录用户不需要初始化拍摄相关任务 。我们一期优化效果达到了 40%,后续几期优化,也收到了不错的效果 。用户侧收益明显,用户(尤其是新用户)0 展示 、0 滑、 0 播放,以及留存等数据都有非常大的提升 。




推荐阅读