作者 | QQ 技术团队
策划 | Tina
背景QQ 作为国民级应用,从互联网兴起就一直陪伴着大家,是很多用户刚接触互联网就开始使用的应用。而 QQ 桌面版最近一次技术架构升级还是在移动互联网兴起之前,在多年迭代过程中,QQ 桌面版也积累了不少技术债务,随着业务的发展和技术的进步,当前的架构已经无法很好支撑对 QQ 的发展了。在 2022 年初,我们下定决心对 QQ 进行全面的技术架构升级,对于这样一个国民级应用的重构,挑战无疑是巨大的。
新版桌面 QQ 自内测以来也受到许多热心网友和行业人士的关注,非常感谢大家在内测过程中提的各种有建设性的建议和反馈。其中,也有一小部分有开发背景的用户对我们采用 Electron 框架表达担心:高内存占用、超大安装包、启动缓慢等。究其原因还是担心新版本 QQ 资源占用大、体验变差,针对用户的担心,我们在内存上进行了专项优化,也取得了一些阶段性的进展,过程中也积累了不少经验,也借此机会分享给大家。
新版 QQ 在内存上的挑战主要表现在以下 4 个方面:
- 产品形态:由 1 个复杂的大面板(100 复杂程度不等的模块)和一系列独立功能窗口构成。窗口与渲染进程一一对应,窗口进程数很大程度影响 Electron 的内存占用。对于那个复杂的大面板, 一旦没有精细控制就很容易导致内存持续走高。
[Electron 窗口多进程]
- 使用习惯:用户长时间挂机。相比用完即走的 Web 页面,QQ 用户在一次登录后,可能会挂机一个月以上。这段期间,如果没有控制好 QQ 内存使用,那么结果可能是内存越占越大、用户交互响应变慢、甚至发生闪退。
- 版本迭代:已经 24 岁的 QQ 拥有众多的功能和特性,过去一年我们一直做这件事:从核心特性开始快速补齐 Windows 版本的功能,同时也有一些高优先级的新功能要上。持续且快速的版本迭代,很可能产生新问题,使性能劣化。
- 应用架构:新版 QQ 依赖一个 NT 核心数据模块(C addon),为 UI 提供本地化的数据服务。QQ 的加载体验能做到如此丝滑,这个模块起到了至关重要的作用。同时,与 NT 的联动优化,也需要拉通客户端 C 开发同学共同完成,当然,会存在一些沟通成本,但不可否认,能把内存占用压下来,客户端同学也付出了非常多的努力。
[桌面端 QQ 整体架构]
在这篇文章中,我们将和大家分享新版 QQ 在内存优化方面的探索和阶段性优化进展。虽然本文的讨论主要集中在 Windows 平台,但由于 Electron 的跨平台特性,大部分优化措施也同样适用于 macOS 和 Linux 平台。
内存现状与目标在着手优化之前,我们结合旧版 QQ 以及其他优秀的桌面应用,给新版 QQ 设定了优化目标:
第一阶段目标,单个进程内存 < 300M。早先因为没有腾出手处理内存问题,代码中存在一些泄漏。长时间挂机后比较容易出现单个进程超过 300M 的情况。我们在去年 9 月份系统地处理过一波内存问题,基本可以保证单个进程的内存占用 < 300M。
第二阶段目标,单进程 <100M,整体 < 300M。整体是指启动 QQ 聊天面板后,6 个进程内存占用之和。内存达标之后才允许交付新版 QQ Windows 版本:
[Windows 任务管理器的 QQ 内存占用详情]
这些进程会随着 QQ 的启动一直存在。我们重点看下这 3 类进程,这也是内存优化的大头:
- node:Electron 的主进程,负责窗口管理、跨进程通信等。包含 NT 核心数据模块,负责与服务端交互,为 UI 提供数据服务。
- renderer:Chromium 内核的渲染进程,负责渲染 UI、提供用户交互等。QQ 启动后,会有 2 个渲染进程:一个是 QQ 大面板,另一个是主进程的窗口池。窗口池是预创建的一个渲染进程。在新开窗口时,可以减少等待时间。
- gpu:Chromium 内核的 GPU 进程。它的主要作用是处理与图形相关的任务,例如渲染网页、播放视频、执行动画等。
设定了目标后,我们先对 QQ 的内存占用情况进行了摸底。我们从用户的角度出发,使用 Windows 任务管理器来观察 QQ 的内存占用情况。我们先从最简单的 “Hello World” 开始,看看 Electron 应用的最低内存需求是多少,以及上限在哪里。结果显示,只需要 68M,并没有达到传说中的几百 M 那么大。
然而,随着使用的深入,比如在 QQ 聊天场景中进行一些操作之后,主进程、GPU 进程和渲染进程三个进程的内存占用就已经达到了 600M。这意味着我们距离目标还有超过 50% 的优化空间。