WWDC-關(guān)于 runtime 的優(yōu)化

前言

此次優(yōu)化是 WWDC-2020 提出的,下面可自行觀看視頻:

關(guān)于 runtime 的改進(jìn)優(yōu)化

用作者話來說,開發(fā)者無需更改任何代碼,也不使用新的API,應(yīng)用程序也會(huì)變得更快。因?yàn)?Apple 在內(nèi)部運(yùn)行時(shí)做了底層數(shù)據(jù)結(jié)構(gòu)的優(yōu)化。

數(shù)據(jù)結(jié)構(gòu)的變化(Class Data Structures Changes)

在磁盤上,在app的二進(jìn)制文件中,類的結(jié)構(gòu)如下:

對(duì)于類的對(duì)象本身,它包含最常訪問的信息:

  • 指向元類、超類和方法緩存的指針。
  • 指向存儲(chǔ)附加信息的更多數(shù)據(jù)的指針,稱為 class_ro_t。其中 Ro 代表只讀。

class_ro_t 包括類的名稱以及方法、協(xié)議和實(shí)例變量的信息。并且 SwiftObjective-C共享這一基礎(chǔ)結(jié)構(gòu)。

當(dāng)類第一次從磁盤加載到內(nèi)存中時(shí),它們一開始是固定的,但是一旦被使用,它們就會(huì)改變。為了理解接下來的類的變化,首先了解一下 Clean MemoryDirty Memory。

Clean Memory 和 Dirty Memory

  • Clean Memory 是指加載后不會(huì)發(fā)生更改的內(nèi)存。class_ro_t 就是屬于 Clean Memory,因?yàn)樗侵蛔x的。

  • Dirty Memory 是指在進(jìn)程運(yùn)行時(shí)發(fā)生更改的內(nèi)存。Class 一旦被使用就會(huì)變成 Dirty Memory,因?yàn)檫\(yùn)行時(shí)會(huì)將新數(shù)據(jù)寫入類中。

特點(diǎn):

Dirty Memory 只要進(jìn)程在運(yùn)行,它就一直存在。而且 iOS 不比 macOS 可以選擇交換 Dirty Memory,iOS 不使用 swap,所以 Dirty MemoryiOS 中代價(jià)很大。

Clean Memory 可以進(jìn)行移除,從而節(jié)省更多的內(nèi)存空間。如果你再次需要它,系統(tǒng)可以從磁盤中 重新加載。

這也是 Class 數(shù)據(jù)被分成兩部分的原因,可以保持干凈的數(shù)據(jù)越多越好,分離出不改變的數(shù)據(jù),存儲(chǔ)為 Clean Memory。

class_rw_t

雖然這些數(shù)據(jù)足以使用,但運(yùn)行時(shí)需要跟蹤有關(guān)每個(gè)類的更多信息,因此當(dāng)類第一次被使用時(shí),運(yùn)行時(shí)還會(huì)為它分配額外的存儲(chǔ)空間。

這個(gè)運(yùn)行時(shí)分配的存儲(chǔ)容量是 class_rw_t,用于讀/寫數(shù)據(jù)。在 class_rw_t 中,存儲(chǔ)了只有在運(yùn)行時(shí)才會(huì)生成的新信息。

First SubclassNext Sibling Class:由于 class_rw_t 中的 First SubclassNext Sibling Class 的特性,所有類都會(huì)鏈接成一個(gè) 樹狀結(jié)構(gòu)。它們?cè)试S運(yùn)行時(shí)遍歷當(dāng)前使用的所有類

MethodsProperties、Protocols:在運(yùn)行時(shí)進(jìn)行添加的,當(dāng) Category 被加載時(shí),它可以向類中添加新的方法,也可以通過 Runtime API 動(dòng)態(tài)添加。

Demangled Name:只有 Swift 才會(huì)使用的字段,甚至 Swift 類都不需要它。除非開發(fā)者想要訪問 SwfitOC 名稱,利用率比較低。

class_rw_t 拆分

因?yàn)?class_rw_t 里面有太多的東西,會(huì)占用 很多 的內(nèi)存??梢詫?不常用 的部分拆分,分配到另一個(gè)擴(kuò)展記錄以供類使用。

在實(shí)際設(shè)備上檢查使用情況時(shí),發(fā)現(xiàn)只有大約 10% 的類真正改變了 Methods。所以,MethodsProperties、Protocols 可以被拆分。

Demangled Name:只有 Swift 才會(huì)使用,也可以被拆分。

因此拆分效果如圖:

class_rw_t 與 class_ro_t 的區(qū)別

  • 當(dāng)類使用了 category 的時(shí)候,那么類就有了 class_rw_t 的結(jié)構(gòu),如果未使用 category,那么類就是一個(gè)單純的 class_ro_t 的結(jié)構(gòu) (Clean Memory)

  • 反之,在類的內(nèi)存結(jié)構(gòu)中如果有 class_rw_t 的結(jié)構(gòu),那么必然會(huì)有 category

案例

實(shí)際驗(yàn)證 XcodeSafariclass_rw_t 占用的內(nèi)存

$ heap Xcode | egrep 'class_rw|COUNT'

占用內(nèi)存如下:

Xcode:

  • class_rw_t 占用字節(jié):2877568

  • class_rw_ext_t 占用字節(jié):203664,占比 7%

Safari:

  • class_rw_t 占用字節(jié):186496

  • class_rw_ext_t 占用字節(jié):27312,占比 15%

總結(jié):class_rw_ext_t 的拆分,可以節(jié)省內(nèi)存開銷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容