騰訊QQ桌面版架構升級:記憶體優化探索與總結

来源:https://www.cnblogs.com/88223100/archive/2023/09/17/Tencent-QQ-Desktop-Architecture-Upgrade-Exploration-and-Summary-of-Memory-Optimization.html
-Advertisement-
Play Games

相比用戶停留時間短、用完即走的 Web 頁面,桌面 QQ 用戶在一次登錄後,可能會掛機一周以上,這段期間,如果沒有嚴格控制好 QQ 記憶體占用,那麼結果可能是用戶交互響應變慢、甚至 Crash。在系統監控工具里,高記憶體占用也會被直觀地反映出來,帶來不好的口碑。MAC QQ 灰度期間,也聽到了一些用戶關... ...


相比用戶停留時間短、用完即走的 Web 頁面,桌面 QQ 用戶在一次登錄後,可能會掛機一周以上,這段期間,如果沒有嚴格控制好 QQ 記憶體占用,那麼結果可能是用戶交互響應變慢、甚至 Crash。
在系統監控工具里,高記憶體占用也會被直觀地反映出來,帶來不好的口碑。MAC QQ 灰度期間,也聽到了一些用戶關於記憶體占用偏高的聲音。
即然不能置若罔聞,那麼必須得痛下決心系統地來一波記憶體占用分析與優化。
在這個過程中,團隊前前後後挖出來了不少優化項,最終,可以讓桌面 QQ 在記憶體占用上達到一個相對較低且穩定的狀態。
本文內容是探索桌面 QQ 記憶體優化上的一個階段性小結,肯定還有更多記憶體優化 trick,歡迎各位多多提意見。

背景

新版桌面 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% 的優化空間。

圖片

這個初步的觀察讓我們看到了目前的挑戰,同時也讓我們看到了優化的可能性。我們有信心,通過精心設計和持續優化,逐步接近甚至超越我們設定的目標。

 

記憶體優化我們都做了什麼

接下來,將重點介紹我們是如何掌控和優化 Electron 的記憶體的。我們的工作主要包括以下幾個方面:

  • 工具分析:首先,我們需要使用不同維度的記憶體分析工具,從 V8 引擎到進程,再到整個應用程式,打通整個鏈路進行多角度的細節分析,以此來定位記憶體使用的瓶頸。
  • 定向優化:在通過工具定位到問題之後,我們會採取一系列的針對性優化策略,包括緩存策略、按需載入、優雅降級等。具體的優化工作我們將在後面進行詳細介紹。
  • 線上監控:在本地或小範圍內驗證通過之後,我們需要廣大用戶的驗證來確認我們的優化措施是否適用於所有場景。然而,如何獲取用戶在 Windows 任務管理器中看到的記憶體使用量是一個挑戰,我們已經做了大量的研究和驗證。
  • 防止性能退化和自動化測試:為了保護我們辛苦得來的優化成果,並避免頻繁的版本迭代影響 QQ 的記憶體目標,我們會藉助開發框架、工具建設、代碼審查等手段來預防性能退化。

分析工具

在進行性能優化之前,我們需要選擇合適的工具來幫助我們分析問題。QQ 的代碼不僅包含 V8 的 JS 部分,還包括許多 Native 的 C++ 模塊。僅依靠 Chromium 開發者工具進行性能分析是不夠的,因此我們需要組合使用多種工具來共同解決問題。

圖片

這些工具如何使用,由於篇幅的關係我們在這裡不做詳細介紹。

圖片
部分記憶體分析工具截圖

定向優化

1) 最大化資源使用率
  • 代碼及靜態資源

桌面版 QQ 的功能邏輯非常複雜,代碼量龐大。雖然代碼不需要通過網路請求載入,本地載入速度通常較快,但載入如此龐大的代碼會占用大量記憶體。因此,仍然需要進行代碼瘦身、靜態資源優化、分包和按需載入等優化措施。

圖片
Devtools > Memory 分析 QQ 主視窗記憶體占用

首先是代碼瘦身。對於第三方包或 SDK,它們往往包含了完備的 Web 相容性及能力,而這些對於 Electron 客戶端來說並不是必需的。因此,我們會對它們進行定製裁剪或獨立實現,以減少代碼的載入。

對於 QQ 的業務代碼,分包策略不完全按照每個頁面(視窗)以及模塊復用次數來進行制訂,更多的情況是按照場景模塊來進行細粒度的定製。以打開一個視窗到進入使用場景為例:1)視窗池中預啟動的視窗頁面只載入必須執行的基礎代碼;2)當打開具體視窗時載入對應的路由後頁面入口代碼;3)當具體使用不同功能時動態載入,如點擊搜索、打開表情面板、轉發消息激活好友選擇器的時候才會分別載入對應功能模塊代碼。

圖片
主視窗業務模塊的拆解

此外,其他靜態資源(如 SVG、base64 圖像)在載入時也會占用不少記憶體,所以我們採取了按需載入的策略:只在可見時載入,不可見時主動銷毀和回收。

圖片
svg及base64資源的string記憶體占用

為了提升執行效率和代碼保護的目的,我們將 JS 代碼轉成了位元組碼。儘管跳過了源碼編譯,直接將位元組碼交給 V8 執行,但在程式報錯還原堆棧等運行時步驟中,V8 仍然會引用源碼字元串。為了去掉這份源碼,我們使用和源碼等長的空格來占位,但通過 devtool 檢查發現這些空格字元串仍會占用不少記憶體空間。最終,我們採取修改和移除 V8 對源碼字元串引用的方式,徹底解決了源碼字元串的記憶體占用問題。

圖片
  • 圖片資源

QQ 作為一款 IM 工具,會涉及到大量的圖片收發。然而,圖片的渲染會占用相當大的記憶體。舉個例子,一張解析度為 4000 x 2750 的圖片,結合設備屏幕像素和聊天區設計尺寸,只需渲染寬度為 567 像素的解析度圖像即可清晰展示。如果以寬度為 4000 像素的解析度渲染,理論上兩者點陣圖所占用的記憶體大小差距可達 50 倍,並且還會因為渲染帶來性能損失。

圖片
圖片尺寸對記憶體影響舉例

在聊天消息列表中的大部分圖片僅僅起到預覽作用,縮略圖渲染就滿足了需要。而僅僅在用戶真正打開圖片查看器放大查看時,才會需要用原圖渲染。

實測在聊天中多張不同大尺寸解析度圖片在展示時,渲染進程和 GPU 進程的記憶體占用有著明顯差別。在收發圖片時,我們會根據屏幕設備信息和計算展示區域所需實際渲染解析度,當原圖解析度超出計算所需值,則先調用壓縮服務進行圖片壓縮,生成渲染所需解析度的縮略圖,併在聊天區域進行渲染上屏。在這個策略的優化下,一般聊天圖片場景測試下來,使用縮略圖比原圖約有 30M ~ 50M 的記憶體優化。

圖片
優化圖片上屏策略
2) 可視區域按需渲染
  • DOM 元素數量

在 DOM 元素使用數量我們也有嚴格的控制,總體採用”所見即占用“的 DOM 渲染策略。在 QQ 大面板中只有視口所見的內容才會渲染對應 DOM 元素。其他所有組件在不渲染展示時,均會移除組件及其 DOM 元素來避免其記憶體開銷。

圖片
大虛擬列表控制DOM數量

尤其對於各個大列表模塊,比如聯繫人列表和群成員列表,DOM 元素都非常多。最開始的內測版本中,使用有大量好友和群聊的 QQ 號,視窗平均 DOM 數達到 13000。我們將 QQ 所有的普通分頁列表替換為虛擬滾動列表,並且對列表滾動 buffer 進行極限壓縮甚至是 0 buffer 。由於不再一味採取空間換時間,沒有 buffer 的情況下必然面對列表滑動性能挑戰,因此也需不斷優化各類 item 組件渲染性能。

此外,我們還通過精簡組件 DOM 層級,移除非核心組件 keep-alive (重新優化渲染性能)等方式,大賬號使用下整體的 DOM 數量從 13000 減少到控制在平均 4000 以內,這部分優化減少約 20M 記憶體。

  • 渲染圖層

渲染圖層方面,在渲染時滿足某些特殊條件的渲染層,會被瀏覽器自動提升為合成層,達到提升渲染性能的目的。但是每個合成層都占用額外的記憶體,應當去掉過量且不必要的合成層來控製圖層帶來的記憶體占用。當然結合渲染性能考量,對於高頻且列表等核心模塊,是可以單獨提升合成層。

圖片
對於渲染合成層的優化處理

在桌面端 QQ 中通過超級調色盤可以為進行色彩換膚,在這個場景中全局各模塊有不少單獨提升的合成層來實現毛玻璃、漸變和紋理效果。另外還有許多不經意間被提升的隱式合成層。通過對不必要的合成層進行移除與合併,整體也優化了約 9.3M 記憶體。

  • 結構化消息

QQ 支持豐富的消息類型,從簡單的文本、圖文消息,到複雜的 lottie 表情、下圖所示的業務可定製的結構化消息等。我們知道 JavaScript 是單線程的,這些消息同時上屏的時候可能會出現過長的上屏任務而導致 UI 卡頓,給到用戶的感受就是切換消息列表卡頓,消息上屏慢等糟糕的體驗。

新版 QQ 針對這類複雜消息上屏,使用了 JavaScript 事件機制結合 WebWorker 來實現消息非同步上屏,並使用 OffscreenCanvas + Worker 池繪製來提升渲染性能。

圖片
結構化消息的處理方案

為了在 Canvas 中實現 CSS 的 Flex 佈局效果,我們採用了跨平臺的佈局解決方案,將 Yoga 編譯成 WebAssembly 運行在 WebWorker 中。Yoga 官方編譯採用的是 asm.js 的方案, 這種方案不支持動態分配記憶體,可以看到它預設分配了一個較高的記憶體,達到了 128M。

圖片
Yoga 渲染引擎的原始記憶體占用

為了優化 WebAssembly 的記憶體占用,我們調整了編譯方式,將 Yoga 編譯成獨立的 wasm 文件,這種方式相比 asm.js 支持動態記憶體分配。同時結合聊天視窗的消息卸載策略,經過不斷的測試調優,在既要保證初始記憶體較少又要儘可能避免記憶體爆髮式增長帶來的性能損耗的前提下,我們把 WebAssembly 的初始記憶體分配優化到 2M,再加上對象共用、享元模式等策略,WebWorker 的記憶體占用有了非常可觀的優化。

圖片
結構化消息渲染引擎優化前後的記憶體占用對比

複雜的聊天消息雖然是必不可少的功能,但是實際的消息量還是遠少於普通的圖文消息,因此在保證用戶體驗的前提下,在合適的條件下適時銷毀 WebWorker 是一個合理的策略,而隨著 WebWorker 被銷毀這個線程所占用的記憶體也能被完全釋放。

3) 性能與體驗平衡
  • Lottie 及動畫方案選型

超級表情採用 Lottie 動畫技術方案,有高清高幀率高質量特點,但同時也為我們帶來了渲染的高成本。為了保證 Lottie 的高幀率和減少 CPU 占用,我們緩存了 Lottie 渲染器生成的動畫幀,記憶體消耗成為了首要問題。

圖片
Lottie 動畫示例

對其進行定量分析,超級表情 Lottie 資源繼承自手機 QQ,尺寸是 512 × 512,動畫幀以 int8 數組存儲,所以一幀動畫為 512 × 512 × 4 = 1MB(乘 4 是因為每個像素由 RGBA 表示),一個普通大小的超級表情,例如慶祝表情,有 160 幀動畫,依據緩存 9/10 幀動畫的策略,慶祝表情會占用 144Mb 記憶體,雖然是可回收的,但也無疑是巨大的記憶體消耗。關註到 Lottie 渲染的記憶體消耗後,我們主要從以下 2 步入手:

  • 緩存的動畫幀尺寸:桌面端 lottie 渲染大小為 120 × 120,考慮到需要保持 Lottie 動畫的高質量,緩存的動畫幀尺寸調整為實際尺寸大小的兩倍,即 240 × 240,降低記憶體消耗 72%。經設計確認,清淅度上也沒有明顯的差異;
  • 緩存策略:緩存 9/10 的動畫幀減少到緩存 3/4,降低記憶體消耗 35%,而且調整之後幀率還能得到保障;

通過以上 2 步,一共降低記憶體消耗 81.8%,慶祝表情從 144 MB 降低到 35 MB。

最後,舊策略對於渲染過且暫時不用的 Lottie 表情,會 buffer 它的第一幀,總共 31 個 Lottie 表情:2.3KB * 31 = 7MB(最多),經評估之後,我們暫時也拿掉了該策略。

圖片
Lottie 動畫緩存首幀對記憶體的影響

另外,桌面 QQ 左側導航欄目,為了與移動端統一體驗,使用 Lottie 動畫來實現,從 memory 面板來看, 4 個 icon 導航條會占用約 6MB 的記憶體。改用 CSS 實現,不僅效果與 Lottie 的幾乎一致,而且這 6MB 的記憶體占用就完全省掉了。

圖片
導航條動畫對記憶體的影響
  • 聊天列表與消息

聊天列表 AIO,作為 QQ IM 模塊中最主要的承載消息數據展示模塊,其滾動體驗必然離不開用戶體驗與記憶體的權衡。

聊天列表在靜態與滾動過程中,維持消息組件的數量多少決很大程度決定整個 QQ 的記憶體占用。消息數據從服務端拉取後會存儲在本地 DB,根據策略會將當前會話的消息數據緩存在記憶體中。

隨著滾動載入,消息緩存占用的記憶體也越多,所以也有一定動態閾值的策略,丟棄滾動方向相反的舊消息,從而將記憶體控制在可接受範圍。如果用戶重新操作又需要載入時,這請求底層向本地磁碟 DB 重新拉取。

圖片
聊天消息列表的載入策略

消息組件實例是記憶體占用的大戶,每條消息組件內部包含頭像/昵稱/狀態/內容等多個實例,如果不對消息實例進行回收銷毀,每百條消息約能帶來 20M+ 的記憶體增量,因此消息實例的回收策略尤為關鍵。

最早版本中對消息上屏沒有丟棄策略,記憶體增量沒有很好控制。於是採用分頁列表,屏內保持固定幾頁消息(約 30 ~ 50 條消息,視屏幕尺寸決定),超過範圍的消息進行丟棄,列表高度由屏內消息直接撐起,用戶通過觸頂或觸底進行上下一頁消息的載入。

但這頁帶來些點問題:一方面隨著觸頂觸底,滾動條頻繁跳動的體驗並不好;另一方面列表高度由不定高的組件渲染消息來維持,不得不始終保留 30 ~ 50 條消息以撐起滾動高度,不可見消息的那部分便造成記憶體的浪費。

使用虛擬列表維持計算高度後,列表不再依賴保持真實消息內容的渲染,理論上我們可以將可視區域以外的消息實例全部銷毀,僅保留用戶可見的消息,最大程度地壓縮消息實例數量,指保留很少的 buffer 消息實例。在實際滾動中由於消息實例在滾動過程被不斷創建和銷毀,占用主線程,影響 UI 繪製和用戶輸入。因此我們還做了:1.對創建銷毀做一定聚合,批量處理消息上屏。2. 精簡優化單條組件的渲染性能。3.不同滾動方向調整上下不同 buffer 大小 等等措施。4、會話切換和視窗聚失焦最小化等操作時對不再使用的消息資源記憶體進行主動回收。

圖片
聊天消息列表的上屏策略

滾動性能和記憶體占用之間需要取得平衡,既要最大程度壓縮上屏消息數量以節省記憶體,又要保證滾動性能體驗。然而經過優化後,本地測試載入 200 條混合種類的消息場景下,從空狀態進入聊天會話中,消息列表記憶體增量從最多 44.2M 降至 6.1M,且滾動靜止後記憶體不會任意增長。

4) Electron 使用姿勢

Electron 給主進程提供了不少對系統能力調用的 API,如托盤、系統通知、macOS 中 dock 欄設置等。但是如果對這些 Electron 能力的使用方式不對,就可能導致不必要的大量記憶體占用甚至是泄漏。

比如 QQ 中,我們通過短間隔定時調用 Tray setImage API 來實現 QQ 托盤的閃爍,如果不註意傳入 string Path 則會每次創建 Image 對象導致記憶體占用,正確的方式應該創建 NativeImage 並緩存,調用 Tray setImage 傳入指定 NativeImage,避免反覆創建 Image 導致的記憶體問題。

圖片
圖片
Windows 托盤圖標記憶體泄漏定位

類似的問題還有在 macOS 中調用 API dock.setIcon 也會持續占用約 20M 的 CGImage 點陣圖記憶體,正確的方案應該是不通過 Electron API 指定,而是通過打包 plist(屬性文件) 指定 dock 欄圖標。

圖片
macOS dock 圖標記憶體泄漏定位

在使用 Electron 的過程中,還存在類似會導致記憶體問題的使用方式,我們需要結合客戶端記憶體工具進行深度挖掘和分析,才能發現和處理這些問題。

5) 消滅記憶體泄漏

我們知道 V8 有自己的垃圾回收機制,雖然它在 GC(垃圾回收)方面有著其各種策略,並做了各種優化從而儘可能的確保垃圾得以回收,但我們仍應當避免任何可能導致無法回收的代碼操作。常見的例子包括:

  • 未移除的監聽器和定時器:在監聽事件處理函數其中引用的不被釋放導致的泄漏。
  • 游離 DOM 未釋放:移出 document 後游離 DOM 仍存在引用導致無法釋放。較多發生於框架的組件銷毀時,相關監聽未取消導致組件沒有釋放的情況。
  • 監控/打點導致的泄漏:在使用 Performance.mark 打點監控時,產生 PerformanceMark 對象,在用完之後沒有手動清除,也會導致記憶體泄漏。
  • error 導致的泄漏:控制台持有被列印對象始終不釋放,導致應用的泄漏。
  • 其他不當的閉包及隱式的全局變數。

以上是桌面 QQ 在早期遇到的常見問題。後續,我們通過代碼檢測手段來防範這類問題的出現。與一般的前端項目不同,由於桌面 QQ 的長周期使用特性,任何緩慢而微小的記憶體泄漏都可能被放大,這也是我們極力把控並阻止任何可能導致記憶體泄漏的代碼引入的原因。

優化結果與線上監控

經過一系列組合優化之後,在我們自己的設備上來看,QQ 的記憶體使用基本是達標了,長時間掛機穩定在 300M 以下,在廣大 QQ 用戶側能否保持這個水平?只有通過線上記憶體及性能的採集監控,才有數據指標來觀測,從而才能對優化有效性進行驗證和決定如何調整優化方向。好在 Electron 提供了 app.getMetics 、 process.getMemoryInfo 等 API 來採集記憶體指標。但需要註意的是這些 API 所採集返回的記憶體值的真實含義,如 getMetric 所採集的到 workingsetSize 和 privateBytes 均不是任務管理器用戶所看到的記憶體。

這裡我們通過 patch 定製改造 Electron getMetics API,來增加不同平臺任務管理器的記憶體類型的指標,並且採集包含了主進程、渲染進程、GPU 進程和工具進程等所有記憶體指標。

圖片

為了避免頻繁採集上報記憶體指標所帶來的的性能消耗,我們設定了一定時間的採集間隔,同時針對使用場景的採集做了抽樣。並將渲染進程 pid 映射尋找視窗名,只在若幹次採集後再做聚合計算,通過 SDK 上報到 prometheus + grafana 的指標觀測平臺。

圖片
記憶體監控整體方案

經過若幹次記憶體性能優化的迭代,目前從線上數據指標來看,新版 Windows QQ 運行的記憶體在主場景下基本控制在 300M, 這個值已經基本達到我們設定的目標。

從登錄後使用過程中的記憶體指標如下:整體應用的記憶體平均占用約為 228M;其中中位數占用約為 211M,90% 分位用戶記憶體占用約為 350M。

圖片
線上記憶體監控視圖

當然,這個目標只是階段性的,我們還會持續針對更多使用場景進行記憶體優化。

防劣化與自動化測試

為了持續關註和保證新版 QQ 項目的性能達標且不劣化,除了比較常規的單元測試、代碼檢查、代碼評審機制、框架內置一些開發規範等手段外,我們還在建設一個防劣化平臺,主要通過自動化的端對端(e2e)測試來持續監控項目集成後的性能變化。

  • 定時對主幹上集成構建的程式進自動化 e2e 測試;
  • 除了對功能的冒煙測試外,針對重點關註的性能指標,構造了對應的帳號和環境,編輯特定的用例,用於採集性能指標;
  • 通過將採集和採樣的指標上報到防劣化的監控平臺,來監控項目集成後的性能變化,如會話切換響應時間、記憶體占用、CPU 使用率等;
  • 監控平臺提供按版本和時間的指標曲線、對比,方便查看和分析性能變化情況。同時打通企業微信機器人,對性能指標情況進行實時推送告警;
  • 根據告警信息對應的版本信息和代碼記錄,排查情況,閉環問題。
圖片
防劣化機制示意圖

這一套機制之前在 內測中的 QQ 頻道桌面端的項目中嘗試應用,運行發現了一些比較典型的代碼異常、crash、oom 問題,證明確實有效。新版 QQ 業務和設計都更複雜,建設好防劣化機制無論是對發現問題的效率,還是對整體的性能和質量都是意義重大的,也是我們團隊當前重點建設、未來持續迭代的重要任務。

圖片
防劣化推送與告警實際應用圖例

總結

可能大家比較關心,為什麼一定要選擇 Electron?其實我們是經過深思熟慮的:

首先,全新 QQ 意味著我們應該專註在功能快速迭代上,否則,以 QQ 的體量戰線會拉得非常長。我們希望最後選擇的跨平臺方案應該是足夠成熟、低開發和使用成本,不需要為了使用框架本身,還需要投入額外巨大的人力成本。這個其實在 React Native、Flutter、Tauri 等跨平臺框架的使用過程中,我們都遇到過類似的問題,除了功能開發,為了把框架生態、周邊、工具鏈建設好,還需要投入巨大的額外成本,Qt 也有類似的問題。而使用 Electron,對於 Web 前端開發同學,基本上是 0 成本,現有的 Web 前端的大部分基建都可以直接復用,而且使用 Web 開發 UI 的效率,在主流技術棧里算是很高的了。並且這幾年主流的桌面端應用基本都選擇了 Electron,如 VScode、Discord、Slack、Skype、Whatsapp、Figma 等等,新的桌面應用基本上也是首選 Electron,另外,Electron 版本的迭代速度和社區氛圍都很線上。

其次,從結果或者解決問題的角度來看,經過一系列優化之後基本可以將 QQ 核心聊天場景的記憶體控制在 300M 以內,150M 的安裝包大小,與舊版純 Native QQ 差別較小。不單單記憶體占用,其他核心體驗,比如切 AIO 的流暢度上要優於舊版 QQ。即便是在今天,QQ 也堅定一年半之前選擇了 Electron。

最後,讓我們再次聚焦在記憶體優化的工作上,下圖是我們在桌面 QQ 中針對 Electron 記憶體優化工作的一個概覽。記憶體優化沒有銀彈,有的只是一步一個腳印深入做下去,芝麻西瓜都要撿,從量變到質變。未來我們完全有信心,憑著已有的經驗和對其技術的理解,守住現在這些成果的同時,進一步優化 QQ 生態下的各個子業務、子模塊的記憶體占用問題。因此,也希望通過我們實踐經驗分享, 讓大家從更多辯證的視角來重新看待 Electron 或類 CEF 的技術方案。

圖片
桌面記憶體優化工作概覽




作者:fred

本文來自博客園,作者:古道輕風,轉載請註明原文鏈接:https://www.cnblogs.com/88223100/p/Tencent-QQ-Desktop-Architecture-Upgrade-Exploration-and-Summary-of-Memory-Optimization.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在設備維修保養管理中,及時通知相關人員是確保設備得到及時維護的關鍵。API介面提供了一個方便的方式來自動發送維修保養通知,以確保工作流程的順利進行。本文將詳細介紹如何使用成熟的API介面來發送設備維修保養通知,以確保設備得到及時的維護,同時提供通俗易懂的步驟和代碼說明。 什麼是API介面? 首先,讓 ...
  • 一、文件管理: 1.1、ls: ​ 顯示文件/目錄屬性 常見參數: -l :列出長數據串,包含文件的屬性與許可權數據等 -a :列出全部的文件,連同隱藏文件(開頭為.的文件)一起列出來(常用) -d :僅列出目錄本身,而不是列出目錄的文件數據 -h :將文件容量以較易讀的方式(GB,kB等)列出來 - ...
  • 1.date文件的備份 2.mysqldump 備份 說明:mysqldump是MySQL資料庫中的一個實用程式,它主要用於轉儲(備份)資料庫。mysqldump通過生成一個SQL腳本文件,包含從頭開始重新創建資料庫所必需的(如 CREATE TABLE和INSERT等),來實現資料庫的備份和轉儲。 ...
  • 1.分組 group by 詳情見,發佈的第七篇博客文章,7- MySQL函數 2.排序 order by 說明:在MySQL中,ORDER BY是一種用於對查詢結果進行排序的關鍵字。它可以根據一列或多列的值,以升序或降序的方式對查詢結果進行排序,使得查詢者可以更加方便 地查看、分析和處理數據。 使 ...
  • 1.分組group by 在MySQL中,GROUP BY的意思是“分組查詢”,它可以根據一個或多個欄位對查詢結果進行分組。 GROUP BY的作用是通過一定的規則將一個數據集劃分成若幹個小的區域,然後針對若幹個小區域進行數據處理。這可以理解為將數據按照某個欄位或者多個欄位進行分組。 使用GROUP ...
  • MySQL資料庫管理 資料庫-->數據表-->行(記錄):用來描述一個對象的信息 列(欄位):用來描述對象的一個屬性 常用的數據類型: int :整型 無符號[0,2^32-1],有符號[-2^31,2^31-1] float :單精度浮點 4位元組32位 double :雙精度浮點 8位元組64位 c ...
  • 在MySQL中,高級查詢是指使用更複雜的查詢語句和操作符來檢索和操作資料庫中的數據。高級查詢可以幫助您更精確地找到所需的信息,並提高查詢的效率和靈活性。 以下是高級查詢的一些常見應用場景和意義: 連接多個表:使用JOIN操作符將多個表連接起來,以便在一次查詢中獲取相關聯的數據。這對於在多個表之間建立 ...
  • 背景: 隨著項目體量越來越大,用戶群體越來越多,用戶的聲音也越來越明顯;關於應用發版之後用戶無感知,導致用戶用的是仍然還是老版本功能,除非用戶手動刷新,否則體驗不到最新的功能;這樣的體驗非常不好,於是我們團隊針對該問題給出了相應的解決方案來處理;技術棧:vue3+ts+vite+ant-design ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...