探究Swift的String底層實現
問題: Swift中的字串在記憶體中是如何儲存的?
- 首先我們來程式碼驗證一下最簡單的字串--"空字串"的記憶體分佈
var empty = "" print("empty \(empty)") print(withUnsafePointer(to: &empty, { $0 }))
列印結果:
1. 檢視Swift.String
原始碼連結, 搜尋"empty"
- 看關鍵程式碼發現底部的
public init
方法呼叫了內部的init
方法, 該初始化方法接收了一個_StringGuts
的物件作為入參. - 原始碼
357
行開始, 也可看到結構體String
持有_StringGuts
作為成員變數. 我們繼續深挖StringGuts
.
2. 檢視StringGuts.swift
原始碼連結, 搜尋"empty".
- 從
_StringGuts
結構體的初始化方法中, 可以看到該結構體持有StringObject
作為成員變數, 撥雲見日, 深挖"StringObject".
3. 檢視StringObject
原始碼連結, 搜尋"empty".
-
在
StringObject
的init(count: variant: discirminator: flags:)
方法中可以看到StringObject
結構體的4個成員變數. -
在建立一個字串的過程中, 都儲存了什麼內容呢?
-
從上面的原始碼可以看到
String
結構體在底層儲存的就是以上4個成員變數的內容. -
初始化方法中
discriminator
成員變數對應的的Nibbles
又是什麼呢? - 可以看到
Nibbles
也是一個列舉型別, 但是這裡只是定義, 原始定義是:
- 可以看到, 這裡呼叫的方法判斷是如果當前是ASCII碼, 那麼當前的Discriminator判別器就是
0xE000_0000_0000_0000
, 如果不是ASCII碼就是0xA000_0000_0000_0000
- 檢視一個空字串的記憶體分佈, 列印結果如下:
- 檢視一個包含中文的字串, 列印結果如下:
-
⭐️綜上, 我們可以看出A, E在這裡是用來標識當前是否是ASCII碼, 其中後面的數字是用來代表當前的多少個字串的長度.
-
_discriminator
佔據4位, 每一位的標識如下:
- 大字串的規則和
Nibbles
的佈局結構如下:
- 對於原生的Swift字串來說, 採取的是
tail-allocated
(尾遞迴)儲存, 也就是在當前例項分配有超出其最後儲存屬性的額外空間, 額外的空間可用於直接在例項中儲存任意資料, 無需額外的堆分配.程式碼驗證如下:
- 接下來我們需要關注的是
0x8000000100003f60
這個值, 根據上面的原始碼分析閱讀, 我們知道當前0x8
標識的是大字串
, 這點我們在原始碼裡也可以找到答案:
- 同時結合
nibbles
在記憶體中的佈局我們知道其中b60:b0
是儲存字串的地址, 當然這個地址要加上偏移量, 這個偏移量是32
, 這裡我們可通過計算器來驗證一下:
下面是ASCII碼十六進位制符號對照表:
- 那麼前面的8個位元組是什麼呢? 我們可以先從初始化的流程來分析:
- 所以可以看到, 除了我們當前的地址和標識位之外, 剩餘的就是
countAndFlags
, 這裡我們可以看到佈局如下:
- 第一個標誌位是
isASCII
, 如果我們修改成中文, 這裡就會改變
- ⭐️綜上, 我們可以發現Small strings(長度小於等於15的小字串)直接存在記憶體中, Large strings(長度大於15的大字串)儲存的是記憶體地址
回答: Small strings(長度小於等於15的小字串)直接存在記憶體中, Large strings(長度大於15的大字串)儲存的是記憶體地址
發文不易, 喜歡點讚的人更有好運氣👍 :), 定期更新+關注不迷路~
ps:歡迎加入筆者18年建立的研究iOS稽核及前沿技術的三千人扣群:662339934,坑位有限,備註“掘金網友”可被群管通過~
- iOS老司機聊聊實際專案開發中的<<人月神話>>
- iOS老司機可落地在中大型iOS專案中的5大接地氣設計模式合集
- iOS老司機的跨端跨平臺Hybrid開發Tips
- iOS老司機的2022年回顧, 聊聊寒冬下的實用<<談判力>>
- iOS老司機可落地的中大型iOS專案中的設計模式優化Tips_橋接模式
- iOS老司機的多執行緒PThread學習分享
- iOS老司機整理, iOSer必會的經典演算法_2
- iOS老司機的<<藍海轉型>>讀書分享
- iOS老司機的<<程式設計師的自我修養:連結、裝載與庫>>讀書分享
- iOS老司機的接地氣演算法Tips
- iOS老司機的RunLoop原理探究及實用Tips
- iOS老司機整理, iOSer必會的經典演算法_1
- iOS老司機的App啟動優化Tips, 讓啟動速度提升10%
- iOS老司機的網路相關Tips
- 戀上資料結構與演算法
- iOS老司機帶你一起把App的崩潰率降到0.1%以下
- 探究Swift的String底層實現
- iOS老司機萬字整理, 可能是最全的Swift Tips
- iOS老司機可落地的中大型iOS專案中的設計模式優化Tips
- 聊一聊Swift中的閉包