網站首頁 編程語言 正文
引言
在上文已經了解了SIL,接下來主要通過Swift源碼和SIL剖析底層。本文主要通過底層源碼探索類和對象在底層的結構
主要內容:
- 對象
- 類
1. 對象
通過源碼中探索Swift對象創建過程以及最終得到的對象結構。
1.1 上層代碼中查找
通過符號斷點調試來查找底層調用方法
源碼:
class WYStudent {
var age: Int = 18
var name: String = "WY"
}
var stu = WYStudent();
1.1.1 查找對象調用方法
通過斷點查看發現是通過__allocating_init()方法實現對象的創建
添加斷點
查看調用方法
1.1.2 設置符號斷點
符號斷點:
查看:
說明:
- 在上面SIL的認識中已經知道了對象是通過__allocating_init()來創建的,在此處打斷點查看
- 在__allocating_init()方法中可以看到會調用swift_allocObject()方法
- 因此接下來就需要在源碼中查看該方法
- __allocating_init()方法中做了兩件事
- 調用swift_allocObject創建對象
- 調用init()初始化對象,這個init方法是類默認提供的,也是默認調用的
1.2 swift_allocObject
說明:
- 通過swift_slowAlloc分配內存,并進行內存字節對齊,傳入開辟的內存空間大小和對齊位數
- 通過HeapObject方法構造一個HeapObject對象,并且綁定到object上
- 因此此時的object就是一個heapObject對象
- 函數的返回值是HeapObject類型,所以當前對象的內存結構就是HeapObject的內存結構
1.3 swift_showAlloc
// Apple malloc is always 16-byte aligned.
# define MALLOC_ALIGN_MASK 15
說明:
- 通過swift_slowAlloc用來分配內存空間
- 這里會通過對齊位數來判斷使用哪種方法來分配空間
- 最小的對齊位數是16字節,如果傳入的位數小于16字節,那么就是用16字節對齊,也就是使用malloc方法
- 如果大于16字節位數,那么使用AlignedAlloc方法
1.4 查看HeapObject結構體
結構體
refCounts查看:
typedef RefCounts<InlineRefCountBits> InlineRefCounts;
//是一個類,所以它的對象就是8個字節
class RefCounts {
std::atomic<RefCountBits> refCounts;//引用計數
...
}
說明:
- 結構體內包含一個成員,metadata
- HeapObject()初始化器,會初始化metadata和refCounts,因此對象中會有這兩種屬性
- 其中metadata類型是HeapMetadata,是一個指針類型,占8字節,其實它就是類信息
- refCounts是引用計數,也占有8個字節
- refCounts的類型是InlineRefCounts
- 而InlineRefCounts是一個類RefCounts的別名
- RefCounts是一個類,所以refCounts占8個字節
1.5 對象內存大小計算
說明:
- metadata占8個字節
- refCounts占8個字節
- 再加上age的8個字節
- name占8個字節
- 所以總共是40個字節
1.6 總結
實例對象的底層結構是HeapObject結構體
默認16字節內存大小,metadata 8字節 + refCounts 8字節
metadata是類信息結構,下面會分析
refCounts是引用計數,后面也會詳細分析
Swift中對象的內存分配流程是:
__ allocating_init --> swift_allocObject_ --> _swift_allocObject --> swift_slowAlloc --> malloc
2. 類
對象在底層中的結構是HeapObject結構體,其第一個屬性為metadata,因此從這個屬性出發來查看類的結構
2.1 查找HeapMetadata
代碼:
using HeapMetadata = TargetHeapMetaData<Inprocess>;
說明:
- 上文可知對象結構體HeapObject包含有HeapMetadata結構體,對象通過它來查找對應的類信息
- 點擊進入HeapMetadata的定義,發現它是TargetHeapMetaData類型的別名
- 并且接收了一個參數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
};
說明:
- TargetHeapMetaData其本質是一個模板類型,其中定義了一些所需的數據結構
- 這個結構體中沒有屬性,只有初始化方法
- 初始化方法中傳入了一個MetadataKind類型的參數,之后就可以返回TargetMetaData對象
- 同時可以看到這里傳入的kind也就是上面的inprocess了
- 該初始化方法構造的對象需要通過該參數來確定
2.3. TargetMetaData
代碼:
說明:
- 在TargetMetaData中可以看到有一個Kind屬性,這是在構建對象時傳入的那個參數
查看MetadataKind
說明:
- 可以看到它是uint32_t類型
類型
說明:
- 進入MetadataKind定義,里面有一個#include "MetadataKind.def"
- 點擊進入,其中記錄了所有類型的元數據
getClassObject方法:
const TargetClassMetadata<Runtime> *getClassObject() const;
//******** 具體實現 ********
template<> inline const ClassMetadata *
Metadata::getClassObject() const {
//匹配kind
switch (getKind()) {
//如果kind是class
case MetadataKind::Class: {
// Native Swift class metadata is also the class object.
//將當前指針強轉為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;
}
}
說明:
- 在TargetMetaData結構體定義中有一個方法getClassObject,它就可以用來獲取類對象,也就是類
- 在方法中的核心邏輯是通過kind來判斷當前是哪種類型,之后返回
- 這里我們需要的是類類型,因此判斷為MetadataKind::Class,就會返回ClassMetadata類型
驗證:
命令:
po metadata->getKind()
得到其kind是Class
po metadata->getClassObject() + x/8g 0x0000000110efdc70
這個地址中存儲的是元數據信息!
說明:
- 傳遞進來的Kind發現可以判斷為類
- 通過方法調用最后得到的是一個類對象,也就是類
- 通過x/8g查看類信息,里面就是存儲的元數據信息
注意:
- TargetMetadata 和 TargetClassMetadata 本質上是一樣的
- 因為在內存結構中,可以直接進行指針的轉換,所以可以說,我們認為的結構體,其實就是TargetClassMetadata
2.4. TargetClassMetadata
代碼:
template <typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
...
//swift特有的標志
ClassFlags Flags;
//實力對象內存大小
uint32_t InstanceSize;
//實例對象內存對齊方式
uint16_t InstanceAlignMask;
//運行時保留字段
uint16_t Reserved;
//類的內存大小
uint32_t ClassSize;
//類的內存首地址
uint32_t ClassAddressPoint;
...
}
說明:
- 包含了很多屬性,這些都屬于類結構信息
- 并且它繼承自TargetAnyClassMetadata
2.5. TargetAnyClassMetadata
代碼:
說明:
- TargetAnyClassMetadata是所有的類結構,不單單是給Swift用的
- 繼承自TargetHeapMetadata,這也證明類本身也是對象
- 提供有isa、superclass、cache、data,和OC的底層類結構完全一樣
原文鏈接:https://juejin.cn/post/7138028713316188167
相關推薦
- 2023-02-12 Pytorch建模過程中的DataLoader與Dataset示例詳解_python
- 2022-04-19 前端開發中幾種存儲方式詳解
- 2021-12-06 linux下ceph分布式安裝使用教程_Linux
- 2022-05-13 python實現簡易圖書管理系統_python
- 2023-09-12 git 忽略掉不需要的文件
- 2022-09-24 詳解ASP.NET中加密和解密的方法_實用技巧
- 2022-03-25 .NET微服務架構CI/CD鏡像自動分發_實用技巧
- 2022-06-22 Python實現npy/mat文件的保存與讀取_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支