網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
引言
在上文已經(jīng)了解了SIL,接下來(lái)主要通過(guò)Swift源碼和SIL剖析底層。本文主要通過(guò)底層源碼探索類和對(duì)象在底層的結(jié)構(gòu)
主要內(nèi)容:
- 對(duì)象
- 類
1. 對(duì)象
通過(guò)源碼中探索Swift對(duì)象創(chuàng)建過(guò)程以及最終得到的對(duì)象結(jié)構(gòu)。
1.1 上層代碼中查找
通過(guò)符號(hào)斷點(diǎn)調(diào)試來(lái)查找底層調(diào)用方法
源碼:
class WYStudent {
var age: Int = 18
var name: String = "WY"
}
var stu = WYStudent();
1.1.1 查找對(duì)象調(diào)用方法
通過(guò)斷點(diǎn)查看發(fā)現(xiàn)是通過(guò)__allocating_init()方法實(shí)現(xiàn)對(duì)象的創(chuàng)建
添加斷點(diǎn)
查看調(diào)用方法
1.1.2 設(shè)置符號(hào)斷點(diǎn)
符號(hào)斷點(diǎn):
查看:
說(shuō)明:
- 在上面SIL的認(rèn)識(shí)中已經(jīng)知道了對(duì)象是通過(guò)__allocating_init()來(lái)創(chuàng)建的,在此處打斷點(diǎn)查看
- 在__allocating_init()方法中可以看到會(huì)調(diào)用swift_allocObject()方法
- 因此接下來(lái)就需要在源碼中查看該方法
- __allocating_init()方法中做了兩件事
- 調(diào)用swift_allocObject創(chuàng)建對(duì)象
- 調(diào)用init()初始化對(duì)象,這個(gè)init方法是類默認(rèn)提供的,也是默認(rèn)調(diào)用的
1.2 swift_allocObject
說(shuō)明:
- 通過(guò)swift_slowAlloc分配內(nèi)存,并進(jìn)行內(nèi)存字節(jié)對(duì)齊,傳入開辟的內(nèi)存空間大小和對(duì)齊位數(shù)
- 通過(guò)HeapObject方法構(gòu)造一個(gè)HeapObject對(duì)象,并且綁定到object上
- 因此此時(shí)的object就是一個(gè)heapObject對(duì)象
- 函數(shù)的返回值是HeapObject類型,所以當(dāng)前對(duì)象的內(nèi)存結(jié)構(gòu)就是HeapObject的內(nèi)存結(jié)構(gòu)
1.3 swift_showAlloc
// Apple malloc is always 16-byte aligned.
# define MALLOC_ALIGN_MASK 15
說(shuō)明:
- 通過(guò)swift_slowAlloc用來(lái)分配內(nèi)存空間
- 這里會(huì)通過(guò)對(duì)齊位數(shù)來(lái)判斷使用哪種方法來(lái)分配空間
- 最小的對(duì)齊位數(shù)是16字節(jié),如果傳入的位數(shù)小于16字節(jié),那么就是用16字節(jié)對(duì)齊,也就是使用malloc方法
- 如果大于16字節(jié)位數(shù),那么使用AlignedAlloc方法
1.4 查看HeapObject結(jié)構(gòu)體
結(jié)構(gòu)體
refCounts查看:
typedef RefCounts<InlineRefCountBits> InlineRefCounts;
//是一個(gè)類,所以它的對(duì)象就是8個(gè)字節(jié)
class RefCounts {
std::atomic<RefCountBits> refCounts;//引用計(jì)數(shù)
...
}
說(shuō)明:
- 結(jié)構(gòu)體內(nèi)包含一個(gè)成員,metadata
- HeapObject()初始化器,會(huì)初始化metadata和refCounts,因此對(duì)象中會(huì)有這兩種屬性
- 其中metadata類型是HeapMetadata,是一個(gè)指針類型,占8字節(jié),其實(shí)它就是類信息
- refCounts是引用計(jì)數(shù),也占有8個(gè)字節(jié)
- refCounts的類型是InlineRefCounts
- 而InlineRefCounts是一個(gè)類RefCounts的別名
- RefCounts是一個(gè)類,所以refCounts占8個(gè)字節(jié)
1.5 對(duì)象內(nèi)存大小計(jì)算
說(shuō)明:
- metadata占8個(gè)字節(jié)
- refCounts占8個(gè)字節(jié)
- 再加上age的8個(gè)字節(jié)
- name占8個(gè)字節(jié)
- 所以總共是40個(gè)字節(jié)
1.6 總結(jié)
實(shí)例對(duì)象的底層結(jié)構(gòu)是HeapObject結(jié)構(gòu)體
默認(rèn)16字節(jié)內(nèi)存大小,metadata 8字節(jié) + refCounts 8字節(jié)
metadata是類信息結(jié)構(gòu),下面會(huì)分析
refCounts是引用計(jì)數(shù),后面也會(huì)詳細(xì)分析
Swift中對(duì)象的內(nèi)存分配流程是:
__ allocating_init --> swift_allocObject_ --> _swift_allocObject --> swift_slowAlloc --> malloc
2. 類
對(duì)象在底層中的結(jié)構(gòu)是HeapObject結(jié)構(gòu)體,其第一個(gè)屬性為metadata,因此從這個(gè)屬性出發(fā)來(lái)查看類的結(jié)構(gòu)
2.1 查找HeapMetadata
代碼:
using HeapMetadata = TargetHeapMetaData<Inprocess>;
說(shuō)明:
- 上文可知對(duì)象結(jié)構(gòu)體HeapObject包含有HeapMetadata結(jié)構(gòu)體,對(duì)象通過(guò)它來(lái)查找對(duì)應(yīng)的類信息
- 點(diǎn)擊進(jìn)入HeapMetadata的定義,發(fā)現(xiàn)它是TargetHeapMetaData類型的別名
- 并且接收了一個(gè)參數(shù)Inprocess
2.2. TargetHeapMetaData
代碼:
//模板類型
template <typename Runtime>
struct TargetHeapMetadata : TargetMetadata<Runtime> {
using HeaderType = TargetHeapMetadataHeader<Runtime>;
TargetHeapMetadata() = default;
//初始化方法
constexpr TargetHeapMetadata(MetadataKind kind)
: TargetMetadata<Runtime>(kind) {}
#if SWIFT_OBJC_INTEROP
constexpr TargetHeapMetadata(TargetAnyClassMetadata<Runtime> *isa)
: TargetMetadata<Runtime>(isa) {}
#endif
};
說(shuō)明:
- TargetHeapMetaData其本質(zhì)是一個(gè)模板類型,其中定義了一些所需的數(shù)據(jù)結(jié)構(gòu)
- 這個(gè)結(jié)構(gòu)體中沒(méi)有屬性,只有初始化方法
- 初始化方法中傳入了一個(gè)MetadataKind類型的參數(shù),之后就可以返回TargetMetaData對(duì)象
- 同時(shí)可以看到這里傳入的kind也就是上面的inprocess了
- 該初始化方法構(gòu)造的對(duì)象需要通過(guò)該參數(shù)來(lái)確定
2.3. TargetMetaData
代碼:
說(shuō)明:
- 在TargetMetaData中可以看到有一個(gè)Kind屬性,這是在構(gòu)建對(duì)象時(shí)傳入的那個(gè)參數(shù)
查看MetadataKind
說(shuō)明:
- 可以看到它是uint32_t類型
類型
說(shuō)明:
- 進(jìn)入MetadataKind定義,里面有一個(gè)#include "MetadataKind.def"
- 點(diǎn)擊進(jìn)入,其中記錄了所有類型的元數(shù)據(jù)
getClassObject方法:
const TargetClassMetadata<Runtime> *getClassObject() const;
//******** 具體實(shí)現(xiàn) ********
template<> inline const ClassMetadata *
Metadata::getClassObject() const {
//匹配kind
switch (getKind()) {
//如果kind是class
case MetadataKind::Class: {
// Native Swift class metadata is also the class object.
//將當(dāng)前指針強(qiáng)轉(zhuǎn)為ClassMetadata類型
return static_cast<const ClassMetadata *>(this);
}
case MetadataKind::ObjCClassWrapper: {
// Objective-C class objects are referenced by their Swift metadata wrapper.
auto wrapper = static_cast<const ObjCClassWrapperMetadata *>(this);
return wrapper->Class;
}
// Other kinds of types don't have class objects.
default:
return nullptr;
}
}
說(shuō)明:
- 在TargetMetaData結(jié)構(gòu)體定義中有一個(gè)方法getClassObject,它就可以用來(lái)獲取類對(duì)象,也就是類
- 在方法中的核心邏輯是通過(guò)kind來(lái)判斷當(dāng)前是哪種類型,之后返回
- 這里我們需要的是類類型,因此判斷為MetadataKind::Class,就會(huì)返回ClassMetadata類型
驗(yàn)證:
命令:
po metadata->getKind()
得到其kind是Class
po metadata->getClassObject() + x/8g 0x0000000110efdc70
這個(gè)地址中存儲(chǔ)的是元數(shù)據(jù)信息!
說(shuō)明:
- 傳遞進(jìn)來(lái)的Kind發(fā)現(xiàn)可以判斷為類
- 通過(guò)方法調(diào)用最后得到的是一個(gè)類對(duì)象,也就是類
- 通過(guò)x/8g查看類信息,里面就是存儲(chǔ)的元數(shù)據(jù)信息
注意:
- TargetMetadata 和 TargetClassMetadata 本質(zhì)上是一樣的
- 因?yàn)樵趦?nèi)存結(jié)構(gòu)中,可以直接進(jìn)行指針的轉(zhuǎn)換,所以可以說(shuō),我們認(rèn)為的結(jié)構(gòu)體,其實(shí)就是TargetClassMetadata
2.4. TargetClassMetadata
代碼:
template <typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
...
//swift特有的標(biāo)志
ClassFlags Flags;
//實(shí)力對(duì)象內(nèi)存大小
uint32_t InstanceSize;
//實(shí)例對(duì)象內(nèi)存對(duì)齊方式
uint16_t InstanceAlignMask;
//運(yùn)行時(shí)保留字段
uint16_t Reserved;
//類的內(nèi)存大小
uint32_t ClassSize;
//類的內(nèi)存首地址
uint32_t ClassAddressPoint;
...
}
說(shuō)明:
- 包含了很多屬性,這些都屬于類結(jié)構(gòu)信息
- 并且它繼承自TargetAnyClassMetadata
2.5. TargetAnyClassMetadata
代碼:
說(shuō)明:
- TargetAnyClassMetadata是所有的類結(jié)構(gòu),不單單是給Swift用的
- 繼承自TargetHeapMetadata,這也證明類本身也是對(duì)象
- 提供有isa、superclass、cache、data,和OC的底層類結(jié)構(gòu)完全一樣
原文鏈接:https://juejin.cn/post/7138028713316188167
相關(guān)推薦
- 2022-11-07 react-native?實(shí)現(xiàn)漸變色背景過(guò)程_React
- 2022-05-23 單點(diǎn)登錄之cas集成sonar的配置方法_相關(guān)技巧
- 2022-10-12 python繪制發(fā)散型柱狀圖+誤差陰影時(shí)間序列圖+雙坐標(biāo)系時(shí)間序列圖+繪制金字塔圖_python
- 2023-01-19 Android?各版本兼容性適配詳解_Android
- 2022-09-13 Nginx如何配置根據(jù)路徑轉(zhuǎn)發(fā)詳解_nginx
- 2022-08-19 vscode遠(yuǎn)程免密登入Linux服務(wù)器的配置方法_Linux
- 2022-08-31 Python無(wú)法用requests獲取網(wǎng)頁(yè)源碼的解決方法_python
- 2023-12-21 npm install 報(bào)錯(cuò)(npm ERR! errno: -4048, npm ERR! c
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支