共计 2623 个字符,预计需要花费 7 分钟才能阅读完成。
背景介绍
性能测试是 SDK 发版的重要依据,VolcRTC 的业务方对于性能指标都比拟器重,对于 RTC 准入有明确的准入规范。因而咱们建设了线下的性能自动化测试零碎,测试过程中咱们发现 VolcRTC 的内存占用较高存在较大的优化空间。
某个版本 1v1 语音通话 VolcRTC 1v1 语音通话内存占用:
占用的资源 | Memory[MB] |
---|---|
Android 高端机 | 17.87 |
Android 中端机 | 17.58 |
Android 低端机 | 16.06 |
iOS 高端机 | 6.19 |
iOS 中端机 | 6.52 |
iOS 低端机 | 5.73 |
为了实现内存优化,首先须要理清两个问题:
- 哪些模块耗费多少内存?
- 如何优化?
内存组成
在答复以上两个问题之前,咱们先理解下内存的次要组成部分有哪些。
在 Android 零碎上,内存次要分为:
下图红框局部为 VolcRTC 通话过程
- Java Heap, 从 Java 代码调配的对象;通话过程中 Java 内存的散布曲线,次要呈锯齿状的周期性变动。联合 VolcRTC 的业务特点,能够晓得这部分内存次要在 JNI 调用时调配长期对象,累计到肯定水平后由零碎的 GC 机制回收。
- Native Heap, 从 C 或 C++ 代码调配的对象。这部分为 VolcRTC 次要内存占用。
- Code, 用于解决代码和资源(如 dex 字节码、通过优化或编译的 dex 代码、.so 库和字体)的内存。VolcRTC 库所占用内存,但不等于动静库的包大小,次要起因在于代码段是按需分页加载的,所以局部代码不会被加载到内存。VolcRTC 是一个动静库,因而 Code 的内存也是在通话过程中次要局部。
优化方向
依据上文的初步剖析,能够确定 VolcRTC 的内存占用次要散布在 Native Heap 与 Code 段。因而咱们明确大体的优化方向为:
- Native 内存优化
- 动静库包体优化
内存归因剖析
哪些模块如何耗费多少内存?
- 内存调配堆栈信息
- 按模块归因
Heapprofd 实现原理
- hook malloc、calloc、realloc、free 等内存调配相干的函数
- 拷贝寄存器与栈内存,存储到共享内存,用于栈回溯
- 依据堆栈信息聚类生成 Trace 文件
模块归因
VolcRTC 归因规定
VolcRTC 次要分为底层媒体引擎与下层 RTC SDK 两局部。媒体引擎的整体架构是以流水线(Pipeline)的模式组成的,每个 Pipeline 由实现不同性能的 Node 形成。咱们能够依据相干的命名空间进行堆栈过滤,再依据软件分层架构进行层层归因。
纯零碎堆栈
VolcRTC 引起的零碎堆栈内存调配,堆栈不蕴含 VolcRTC 符号信息,无奈按前述规定归类,须要归类到由 VolcRTC 引起的零碎内存调配。
归因示例
内存调配堆栈特色个别为栈底为__pthread_start(void*)
,栈顶为内存存调配办法,两头为 VolcRTC 堆栈信息。依据堆栈信息,联合归因规定而后层层向上归因,造成一个树状的构造,精确剖析每一个 Pipeline、每一个 Node、每一个类型的对象所占用的内存大小。
碰到的问题
Hook malloc 失去的内存大小与 Native Heap 大小不统一
malloc 向内存分配器申请的内存,跟程序运行时传入的 size 统一。
内存分配器向操作系统申请的内存按页调配,个别每页为 4K,Native Heap 统计的是这部分的内存大小。
因为内存分配器的须要重复调配与开释内存,不可避免的产生内存空隙也就是内存碎片,另外内存分配器会缓存一部分小内存块以晋升内存调配效率。
语音通话内存剖析
通过性能自动化测试工具,生成剖析报告。基于剖析报告咱们绘制语音通话内存全景图,再通过全景图辨认出内存占用较高的几个模块,指引优化方向。
内存优化
编译优化
包大小会间接影响到内存大小,因而优化包大小也能够无效缩小内存大小。通过关上 LTO、Oz 等编译选项,联合线下性能自动化测试评估是否对性能指标有负面影响来决定须要开启的编译优化选项。编译优化后 Android 端动静库包体缩小了 900KB,通话过程内存优化 850KB 左右。
按需动态分配
VolcRTC 作为一个通用性能的 SDK,对于每个特定场景会有很多冗余逻辑与性能,这些逻辑与性能都存在较多的预分配内存。对应的优化计划是:
- 正当代码组件化,将不同的性能形象成组件做到灵便组装与按需加载,如:AI 降噪性能内置的数据和模型会占用较大的内存空间。
- 内存尽量按需动态分配。如:AEC 回声打消在不同场景下有不同的算法,须要依据理论的场景按需分配内存,缩小过多的内存预调配。
设置正当的缓存大小
不合理的缓存大小也会引起不必要的内存节约。通过内存的归因剖析,联合不同场景的业务个性,设置更加正当的缓存大小,能够缩小内存占用。例如:RTC 采纳了 RTP 包重传机制来反抗网络丢包,为了实现重传机制,须要缓存肯定数量的包,缓存的数量须要跟进帧长、实时性要求等业务个性来设置正当的值。
正当的算法和数据结构设计
正当的算法和数据结构也能够无效升高内存。在保障计算准确性的前提下,通过缩小数据值域范畴,应用内存空间占用更小的数据类型来实现算法,比方统计与工夫相干的数据时应用绝对工夫而非相对工夫、空间音频算法通过定点化应用 short
类型代替浮点型数据。另外数据结构设计时须要思考内存对齐问题。
优化成果
1v1 语音通话
占用的资源 | 优化前 Memory[MB] | 优化后 Memory[MB] |
---|---|---|
Android 高端机 | 17.87 | 13.59 |
Android 中端机 | 17.58 | 13.98 |
Android 低端机 | 16.06 | 12.93 |
iOS 高端机 | 6.19 | 3.87 |
iOS 中端机 | 6.52 | 3.84 |
iOS 低端机 | 5.73 | 3.14 |
本次内存优化,咱们摸索了 RTC 场景下性能归因剖析驱动性能优化的实际。能够总结出以下教训:
- 结构稳固的测试用例
- 建设性能折损的数据归因模型
- 基于归因模型辨认热点性能问题,造成优化计划
- 从 1v1 通话开始剖析,而后逐渐到多人、百人千人。
退出咱们
字节跳动 RTC 团队,作为寰球当先的音视频团队,咱们致力于提供寰球互联网范畴内高品质、低延时的实时音视频通信能力,目前曾经撑持了抖音、TikTok、清北网校、字节系游戏,视频会议等多个场景的利用,服务 10 亿用户,用户遍布寰球每一个角落。
咱们是 RTC Client(客户端)部门, 致力于保护多个性能 / 平台的 SDK 和最佳实际,满足灵活性和易用性的要求,在音视频通信、行业利用、信令等方向造成本人的特色,期待优良同学的退出
扫码查看 RTC Client 在招岗位
参考文档:
Heapprofd: https://perfetto.dev/docs/desig