携手创造,一起生长!这是我参与「日新计划 8 月更文应战」的第33天,点击检查活动详情
在上文现已了解了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<typenameRuntime>
structTargetHeapMetadata:TargetMetadata<Runtime>{
usingHeaderType=TargetHeapMetadataHeader<Runtime>;
TargetHeapMetadata()=default;
//初始化办法
constexprTargetHeapMetadata(MetadataKindkind)
:TargetMetadata<Runtime>(kind){}
#ifSWIFT_OBJC_INTEROP
constexprTargetHeapMetadata(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办法:
constTargetClassMetadata<Runtime>*getClassObject()const;
//********具体实现********
template<>inlineconstClassMetadata*
Metadata::getClassObject()const{
//匹配kind
switch(getKind()){
//假如kind是class
caseMetadataKind::Class:{
//NativeSwiftclassmetadataisalsotheclassobject.
//将当时指针强转为ClassMetadata类型
returnstatic_cast<constClassMetadata*>(this);
}
caseMetadataKind::ObjCClassWrapper:{
//Objective-CclassobjectsarereferencedbytheirSwiftmetadatawrapper.
autowrapper=static_cast<constObjCClassWrapperMetadata*>(this);
returnwrapper->Class;
}
//Otherkindsoftypesdon'thaveclassobjects.
default:
returnnullptr;
}
}
阐明:
- 在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<typenameRuntime>
structTargetClassMetadata:publicTargetAnyClassMetadata<Runtime>{
...
//swift特有的标志
ClassFlagsFlags;
//实力目标内存大小
uint32_tInstanceSize;
//实例目标内存对齐方式
uint16_tInstanceAlignMask;
//运行时保留字段
uint16_tReserved;
//类的内存大小
uint32_tClassSize;
//类的内存首地址
uint32_tClassAddressPoint;
...
}
阐明:
- 包括了许多特点,这些都归于类结构信息
- 而且它承继自TargetAnyClassMetadata
2.5. TargetAnyClassMetadata
代码:
阐明:
- TargetAnyClassMetadata是一切的类结构,不单单是给Swift用的
- 承继自TargetHeapMetadata,这也证明类自身也是目标
- 供给有isa、superclass、cache、data,和OC的底层类结构彻底相同