Swift類和對(duì)象的底層探索分析
引言
在上文已經(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ì)齊,傳入開(kāi)辟的內(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)完全一樣
以上就是Swift類和對(duì)象的底層探索分析的詳細(xì)內(nèi)容,更多關(guān)于Swift類和對(duì)象的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
通過(guò)Notification.Name看Swift是如何優(yōu)雅的解決String硬編碼
這篇文章主要給大家介紹了通過(guò)Notification.Name看Swift是如何優(yōu)雅的解決String硬編碼的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08Swift仿選擇電影票的效果并實(shí)現(xiàn)無(wú)限/自動(dòng)輪播的方法
這篇文章主要給大家介紹了關(guān)于Swift仿選擇電影票的效果并實(shí)現(xiàn)無(wú)限/自動(dòng)輪播的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08Swift?中的?Actors?使用及如何防止數(shù)據(jù)競(jìng)爭(zhēng)問(wèn)題(示例詳解)
Swift中的Actors旨在完全解決數(shù)據(jù)競(jìng)爭(zhēng)問(wèn)題,但重要的是要明白,很可能還是會(huì)遇到數(shù)據(jù)競(jìng)爭(zhēng),本文將介紹Actors是如何工作的,以及你如何在你的項(xiàng)目中使用它們,感興趣的朋友跟隨小編一起看看吧2023-06-06swift指針及內(nèi)存管理內(nèi)存綁定實(shí)例詳解
這篇文章主要為大家介紹了swift指針及內(nèi)存管理內(nèi)存綁定實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Swift版使用ThPullRefresh實(shí)現(xiàn)下拉上拉刷新數(shù)據(jù)
這篇文章主要介紹了Swift版使用ThPullRefresh實(shí)現(xiàn)下拉上拉刷新數(shù)據(jù),需要的朋友可以參考下2016-01-01Swift算法之棧和隊(duì)列的實(shí)現(xiàn)方法示例
Swift語(yǔ)言中沒(méi)有內(nèi)設(shè)的棧和隊(duì)列,很多擴(kuò)展庫(kù)中使用Generic Type來(lái)實(shí)現(xiàn)?;蚴顷?duì)列。下面這篇文章就來(lái)給大家詳細(xì)介紹了Swift算法之棧和隊(duì)列的實(shí)現(xiàn)方法,需要的朋友可以參考學(xué)習(xí),下面來(lái)一起看看吧。2017-03-03Swift開(kāi)發(fā)之使用UIRefreshControl實(shí)現(xiàn)下拉刷新數(shù)據(jù)及uirefreshcontrol使用
本文給大家介紹使用UIRefreshControl實(shí)現(xiàn)下拉刷新數(shù)據(jù),及UIRefreshControl的使用步驟,對(duì)本文感興趣的朋友一起學(xué)習(xí)吧2015-11-11