聊聊 MIUI 的「原子內存」怎樣解決「殺后臺」的問題?
比起最近雷布斯的個人演講,其實我更好奇 MIUI 12.5 增強版(超級 Bug-list 修復版)推出的那四個性能優化項目:
焦點計算 - 處理器智能調度機制
原子內存 - 精細化內存管理機制
液態存儲 - 文件存儲管理機制
智能均衡 - 對旗艦硬件性能的智能調配
作為技術愛好者,這個 「原子內存」 還真是提起了我的興趣,因為其他三項還算比較好理解。畢竟內存管理這件事,是操作系統領域幾乎永恒的課題。
▍官方解釋
我們先來了解下 MIUI 官方網站是如何介紹原子內存的。官網的海報動效還是闡釋得比較清晰明了(辛苦設計師小姐姐,不知道又加了多少班)。
*開始是幾個獨立的應用各自占有一定的內存,看看這綠,這不就是微信綠。看看這藍,支付寶?看看這橙,這啥,淘寶吧估計是,肯定不是小米自己。
然后,第二步是拆分應用內存,結束不重要的任務,剛才還是整塊的內存占用現在在邏輯上被劃分為了大小不等(即不同功能占用內存大小不同)的幾塊。這一步其實就是核心了,如何來劃分呢?按什么維度劃分呢?有沒有可能劃分失誤反而影響用戶體驗呢?我們后面來聊。
第三步,根據場景,進一步精細壓縮。這一步也很關鍵,不僅能結束優先級較低的任務,還能對剩余的任務進行內存占用的壓縮。聽起來有點玄乎,其實問題還是和第二步類似,如何對內存進行壓縮?系統如何知道要壓縮哪些內容呢?
帶著上面這些問題,我們來簡單聊一聊 MIUI 可能會如何實現這個原子內存,也即是說,以下內容均是基于個人經驗提出的一些猜想,描述盡可能不那么硬核。
▍原理猜想
我們知道,現代操作系統基本都有進程(process)和線程(thread)的概念,用書本上的話說就是:
進程是資源分配的*小單位,線程是 CPU 調度的*小單位。
那么二者的關系,簡單概括便是:一個運行中的應用程序就可以包含多個進程,一個進程又可以包含多個線程。
拿微信舉例來說,主功能聊天是一個進程,內置瀏覽器又是另一個進程,進程之間可以進行通信,但又可以互不影響,比如瀏覽器崩潰了,不影響你聊天,這也是多進程的好處之一。然后,在聊天進程內部,你下載表情包時會開啟另一個線程來完成任務,而不會影響你的 UI 渲染線程,保證了交互的流暢性,這就是多線程的好處。
大致了解這些基本概念后,我們就可以繼續思考 MIUI 的原子內存了。
Android 系統基于 Linux,當然也有進程的概念。我們平時俗稱的 「殺進程」,一般就是指在最近任務中劃掉相應的應用來終止其運行,在你劃掉的那一瞬間,系統會殺掉此應用相關聯的所有進程。而我們俗稱的 「被殺后臺」,就是應用在置于后臺且不可見的時候,被系統為了節約內存等資源而殺掉,這對用戶而言是一種被動的殺進程,某種程度上比較影響使用體驗。
在 Android 的官方文檔中關于內存分配有這么一段話:
Android 平臺在運行時不會浪費可用的內存。它會一直嘗試利用所有可用內存。例如,系統會在應用關閉后將其保留在內存中,以便用戶快速切回到這些應用。因此,通常情況下,Android 設備在運行時幾乎沒有可用的內存。要在重要系統進程和許多用戶應用之間正確分配內存,內存管理至關重要。
其實這個解釋和 Apple 官方之前建議用戶不要頻繁地手動殺進程是一個道理。因為應用啟動,進程重新創建的開銷是很大的。此外,接觸過 Android 開發的同學都知道,系統在內存不足的時候也會盡可能地通知各應用,給了你 「體面」 處理自己的機會。
然而,很多時候國產手機廠商也是不得已而為之,因 Android 應用可以在后臺運行的特性,不管是各類巨無霸應用,還是小而美應用,都在努力讓自己在后臺保活而不遵守開發規范,生怕用戶離它們而去。但這樣爭奇斗艷的后果就是用戶設備續航能力急劇下降,挨罵的往往就是手機系統廠商了。
「原子內存」 想解決的便是這個問題,既能讓更多的應用不被系統完全殺掉,也能減少系統資源的占用,在功耗和功能之間取得一個相對平衡。
拆分內存
其實在 Android 應用層面的開發當中,中小型應用的開發者日常很少會接觸到進程的概念,更多的是 Android 自己抽象的一套開發框架。在其設計架構中, Google 給開發者和用戶提供了 「四大組件」:
Activity - 可簡單理解成我們打開的每一個活動頁面,用于處理用戶交互的邏輯
Service - 服務,和 Activity 的邏輯結構類似,只不過沒有界面,比如用于播放音樂、下載文件等
BroadcastReceiver - 可理解為,Android 系統就是一個巨大的世界頻道,每個應用都可以用小喇叭廣播消息,當然也需要接收消息
ContentProvider - 數據存儲和提供的組件,內含標準接口,不同應用之間可通過此來共享內容
這些組件是 Android 開發的基礎,對于任意一個組件,它都可以獨占一個進程(比如我們上面提到的內置瀏覽器 WebView),也可以和其他組件共享同一個進程,大多數情況都是后者。組件的本質也就是系統創建的一個內存對象,同時,每個組件都有自己的生命周期,在應用進程不被殺掉之前,可以提前結束(比如你打開登錄頁面完成登錄,這個 Activity 的使命就完成了,可以被系統回收資源)。
所以在我*時間看到 MIUI 原子內存的宣傳時,就想到了對四大組件的精細化查殺。拆分內存這一行為可能實質上就是把應用內的各個組件進行分類并按優先級排序,銷毀低優先級的組件,保證用戶可見和正在使用的組件活著就行了,如此就能節省很多內存。當用戶需要再次使用某組件<愛尬聊_尬聊百科>時,重新創建啟動便是。
又拿微信來舉例,當你掃碼支付后,又回到聊天界面,聊了幾句再把微信置于后臺,這時候你去干別的事情了,系統是不是可以把剛才支付相關的資源都回收掉呢?
當然,如果銷毀和創建的行為過于頻繁,也會消耗不少的系統資源,所以我猜測除了設計組件優先級等基本策略,還會有一些機器學習的玩法在里面, 更精準地識別哪些可以被銷毀 。在用戶使用過程中體驗會越來越好,這是一個雙向正反饋的過程。
最近在 MIUI 的官方論壇也看到一些解釋提到「進程級」查殺,其實這個就更好理解了,因為本身很多業務相關性強的組件就在同一個進程內,一個大型應用往往有很多進程在同時運行,那么系統也可以殺掉某些暫時用不到的進程(相當于還能一次性銷毀多個組件),而非粗暴地殺掉整個應用導致用戶回來時一切都要重來。
精細壓縮
說到壓縮,我們可以從*基本的一些解釋中了解原理:
它就是移除多余的空白字符,插入單個的重復字符指出一個字符串中重復的字符,以及將小型的位串用頻繁使用的字符替代。
壓縮其實是一個很樸素的概念,當你知道下一秒的畫面跟這一秒一致時,是不是可以少存儲幾幀數據。在內存上,也是類似的方法,它是真正能夠節約物理空間的。
在 MIUI 的海報中,有個非常關鍵的前提就是:根據場景。也就是說,并不是無腦地對所有內存占用進行壓縮,而是根據用戶使用的場景,來判斷哪些進程或者組件所占用的內存可以壓縮,哪些*好不要壓縮,一切以用戶體驗為前提。這個壓縮的策略,和上述的拆分內存類似,可能也會有機器學習的施展空間,當然,用黑白名單來進行簡單粗暴的實現也不是不可以。
精細壓縮這一步,從 Android 系統的體系結構來講,總體可以分為兩方面,一是交換壓縮,二是垃圾回收。
交換壓縮
先看看官方介紹:
Android 設備包含三種不同類型的內存:RAM、zRAM 和存儲器。
RAM 是*快的內存類型,但其大小通常有限。高端設備通常具有*大的 RAM 容量。
zRAM 是用于交換空間的 RAM 分區。所有數據在放入 zRAM 時都會進行壓縮,然后在從 zRAM 向外復制時進行解壓縮。這部分 RAM 會隨著頁面進出 zRAM 而增大或縮小。設備制造商可以設置 zRAM 大小上限。
存儲器中包含所有持久性數據(例如文件系統等),以及為所有應用、庫和平臺添加的對象代碼。存儲器比另外兩種內存的容量大得多。在 Android 上,存儲器不像在其他 Linux 實現上那樣用于交換空間(swap),因為頻繁寫入會導致這種內存出現損壞,并縮短存儲媒介的使用壽命。
我們可以看出,zRAM 是內存壓縮的關鍵所在,相當于在內存上劃分出一小塊區域用于非活躍內存占用的壓縮存儲。這個 「z」,大概就是 zip 的意思吧。所以,在內存壓縮的底層實現上,原生 Android 已經搞定了,MIUI 不需要自行實現這些內存管理機制,*多是在此基礎上根據用戶使用場景進行算法優化或者動態調整配置。
這里特別要注意的是,官方文檔提到:在 Android 上,存儲器不像在其他 Linux 實現上那樣用于交換空間。這一點也否認了最近網上關于 MIUI 原子內存的討論中 「就是 Linux 的 swap 機制而已」 之類的看法。
我個人認為,Linux 的 swap 機制不會特別適用于移動設備,因為移動設備的存儲器基本上都是類似 SSD 的閃存,用作交換空間來存取內存數據是非常減壽的,對手機來說,閃存壽命下降就意味著卡頓。即便是現在的電腦,也不會設置那么大的 swap 空間了,因為很多電腦內存本身就很大。
垃圾回收
我們每一個應用都運行在一個獨立的 Android 虛擬機之上,所以應用的每一個進程也可叫做虛擬機進程。Android 虛擬機可以粗淺地看作 Java 虛擬機(JVM)的魔改版本,它不能運行原生 Java 程序。垃圾回收(GC)是 JVM 內存管理的核心機制之一。這里就不贅述了,簡單來說就是系統對內存單元的整理和清除。
垃圾回收和剛才的交換壓縮一樣,它們管理內存的粒度都是 「內存頁(page)」,而不是進程和 Android 組件了,對于上層的應用來說,是沒有什么感知的,系統底層在默默地自我調節。
MIUI 原子內存在垃圾回收層面應該不會去做什么改動,因為 GC 機制比較底層,而且也相對成熟穩定,MIUI 做的事情更多是用戶層面的,業務層面的,屬于 GC 的上層調用者。
精細壓縮可能會在何時觸發、如何更有效地觸發垃圾回收上面下功夫。
▍后話
做了這么多猜測,其實也沒有特別深入的技術細節討論,但我在查閱研究過程中,還是能感受到 MIUI 在系統層面的努力,而不僅僅限于做 「UI」。畢竟這么花里胡哨的功能命名都唱出來了,怎么也得有點干貨才行吧。
此外,寫完了我才想到忘了提及以前的 Android 玩機工具寫輪眼,它的主要功能就是由用戶自行決定銷毀哪些組件,MIUI 原子內存或許也從中借鑒了一些思路。
還有一點收獲就是,現在我們可以在很多移動設備用戶場景遇到 AI 技術的落地或者是落地的可能性,借此機會,有空的話可以再跟大家聊聊端側 AI。
13 號當晚我也順利升級到了這個 MIUI 12.5 增強版,感受了一下,同時開 10 個常用 App,后臺被殺的情況確實有所改善,而且剩余內存也比以前多了。對普通用戶來說這就是簡單真實的感受,有效果,說明有點東西。