理解如何實(shí)現(xiàn)才能更好地去理解性能
內(nèi)容概覽
- 內(nèi)存分配
- 引用計(jì)數(shù)
- 方法分發(fā)
- 協(xié)議類型
- 泛型代碼
- 總結(jié)

內(nèi)存分配
在棧上分配、回收內(nèi)存時(shí),只需要移動(dòng)棧指針即可完成操作。操作的成本如同給一個(gè)整型變量賦值。
在堆上分配內(nèi)存時(shí),需要在復(fù)雜的堆數(shù)據(jù)結(jié)構(gòu)中尋找未被使用的大小適合的內(nèi)存。
在堆上回收內(nèi)存時(shí),需要找到合適的位置,然后才能插入內(nèi)存。
很明顯,在堆上操作的成本比在棧上的更高。
除此之外,多個(gè)線程可以同時(shí)在堆上分配內(nèi)存,所以堆需要使用鎖或其他同步機(jī)制以保證完整性。
這就導(dǎo)致了更嚴(yán)重的性能消耗。
內(nèi)存分配示例
使用 struct






使用 class








使用 struct 優(yōu)化內(nèi)存分配

請(qǐng)注意,String中的字符(Character)存儲(chǔ)在堆內(nèi)存中!

這里,使用 struct 保證內(nèi)存分配在棧上進(jìn)行,使代碼更安全也更高效!
引用計(jì)數(shù)
引用計(jì)數(shù)除了加減操作,還有以下操作:
- 間接操作
- 線程安全

為了執(zhí)行 retain, release 操作,Swift 需要在堆內(nèi)存中進(jìn)行引用計(jì)數(shù)。





優(yōu)化引用計(jì)數(shù)的示例



方法分發(fā)
方法分發(fā)分為兩種:
- 靜態(tài)分發(fā)
- 在運(yùn)行時(shí),直接運(yùn)行方法的實(shí)現(xiàn)部分
- 可以進(jìn)行內(nèi)聯(lián)(代碼直接嵌入)或其他優(yōu)化操作
- 動(dòng)態(tài)分發(fā)
- 在運(yùn)行時(shí),需要在函數(shù)表(V-Table)查找實(shí)現(xiàn)部分
- 找到實(shí)現(xiàn)部分后,才能執(zhí)行
- 無(wú)法進(jìn)行內(nèi)聯(lián)或其他優(yōu)化操作
內(nèi)聯(lián)優(yōu)化示例


以上優(yōu)化有效地避免了兩個(gè)函數(shù)的棧內(nèi)存分配。
基于繼承的多態(tài)



至此,我們可以看到明顯的性能消耗差異。
協(xié)議類型
沒(méi)有繼承和引用的多態(tài)


每個(gè)實(shí)現(xiàn)協(xié)議的類型都有一個(gè) Protocol Witness Table (PWT),在這個(gè)表里可以找到函數(shù)的實(shí)現(xiàn)部分。
Swift 使用了一種特殊的內(nèi)存布局 Existential Container 來(lái)存儲(chǔ)實(shí)現(xiàn)了協(xié)議的不同類型。

Existential Container 中的前3個(gè)字(word)是 valueBuffer。

像 Point 這種小類型,只需要占用2個(gè)字。

而 Line 需要4個(gè)字,Swift 使用堆內(nèi)存存儲(chǔ)值,然后在 Existential Container 中存儲(chǔ)值的指針。
因?yàn)?Point 和 Line 類型的差異性,Existential Container 需要使用 Value Witness Table 來(lái)管理這些值的生命周期,每個(gè)類型有一個(gè) Value Witness Table。





如果感興趣,建議下載 官方PDF 查看詳細(xì)流程。
使用間接存儲(chǔ)來(lái)優(yōu)化大的值類型:

泛型代碼

泛型代碼的特征:
- 靜態(tài)的多態(tài): 在調(diào)用的地方使用具體的類型
- 每種類型都有單獨(dú)的調(diào)用上下文
- 隨著調(diào)用鏈替換類型

泛型方法的實(shí)現(xiàn):
- 共享的實(shí)現(xiàn)
- 使用 Protocol/Value Witness Table
- 每種類型都有單獨(dú)的調(diào)用上下文:傳遞 Table


泛型特殊化:
- 靜態(tài)的多態(tài): 在調(diào)用的地方使用具體的類型

- 創(chuàng)建類型專屬版本的方法

- 每個(gè)類型都有自己專屬的方法

- 可以進(jìn)行壓縮優(yōu)化



何時(shí)進(jìn)行特殊化?
- 在調(diào)用的地方
- 定義是可見(jiàn)的
開(kāi)啟 Whole Module Optimization 可以獲得更多優(yōu)化的機(jī)會(huì)。
總結(jié)
使用合適的抽象,以降低動(dòng)態(tài)運(yùn)行時(shí)的消耗
- 使用值類型:struct
- 引用類型: 特性 或 面向?qū)ο箫L(fēng)格的多態(tài)
- 泛型:靜態(tài)的多態(tài)
- 協(xié)議:動(dòng)態(tài)的多態(tài)
使用間接存儲(chǔ)解決大的值類型的引用問(wèn)題
參考內(nèi)容:
Understanding Swift Performance
轉(zhuǎn)載請(qǐng)注明出處,謝謝~