前言
此次優(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í)例變量的信息。并且 Swift 和 Objective-C共享這一基礎(chǔ)結(jié)構(gòu)。
當(dāng)類第一次從磁盤加載到內(nèi)存中時(shí),它們一開始是固定的,但是一旦被使用,它們就會(huì)改變。為了理解接下來的類的變化,首先了解一下
Clean Memory和Dirty 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 Memory在iOS中代價(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 Subclass和Next Sibling Class:由于class_rw_t中的First Subclass和Next Sibling Class的特性,所有類都會(huì)鏈接成一個(gè)樹狀結(jié)構(gòu)。它們?cè)试S運(yùn)行時(shí)遍歷當(dāng)前使用的所有類
Methods、Properties、Protocols:在運(yùn)行時(shí)進(jìn)行添加的,當(dāng)Category被加載時(shí),它可以向類中添加新的方法,也可以通過Runtime API動(dòng)態(tài)添加。
Demangled Name:只有Swift才會(huì)使用的字段,甚至Swift類都不需要它。除非開發(fā)者想要訪問Swfit的OC名稱,利用率比較低。
class_rw_t 拆分
因?yàn)?class_rw_t 里面有太多的東西,會(huì)占用 很多 的內(nèi)存??梢詫?不常用 的部分拆分,分配到另一個(gè)擴(kuò)展記錄以供類使用。
在實(shí)際設(shè)備上檢查使用情況時(shí),發(fā)現(xiàn)只有大約
10%的類真正改變了Methods。所以,Methods、Properties、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)證
Xcode和Safari的class_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)存開銷。