携手创造,一起生长!这是我参与「日新计划 8 月更文应战」的第33天,点击检查活动详情

在上文现已了解了SIL,接下来首要经过Swift源码和SIL分析底层。本文首要经过底层源码探究类和目标在底层的结构

首要内容:

  1. 目标

1. 目标

经过源码中探究Swift目标创立过程以及终究得到的目标结构。

1.1 上层代码中查找

经过符号断点调试来查找底层调用办法

源码:

class WYStudent {
    var age: Int = 18
    var name: String = "WY"
}
var stu = WYStudent();

1.1.1 查找目标调用办法

经过断点检查发现是经过__allocating_init()办法实现目标的创立

增加断点

Swift底层探索(二)Swift类和对象的底层分析

检查调用办法

Swift底层探索(二)Swift类和对象的底层分析

1.1.2 设置符号断点

符号断点:

Swift底层探索(二)Swift类和对象的底层分析

检查:

Swift底层探索(二)Swift类和对象的底层分析

阐明:

  • 在上面SIL的知道中现已知道了目标是经过__allocating_init()来创立的,在此处打断点检查
  • 在__allocating_init()办法中能够看到会调用swift_allocObject()办法
  • 因而接下来就需求在源码中检查该办法
  • __allocating_init()办法中做了两件事
    • 调用swift_allocObject创立目标
    • 调用init()初始化目标,这个init办法是类默许供给的,也是默许调用的

1.2 swift_allocObject

Swift底层探索(二)Swift类和对象的底层分析

阐明:

  • 经过swift_slowAlloc分配内存,并进行内存字节对齐,传入拓荒的内存空间大小和对齐位数
  • 经过HeapObject办法结构一个HeapObject目标,而且绑定到object上
  • 因而此刻的object便是一个heapObject目标
  • 函数的回来值是HeapObject类型,所以当时目标的内存结构便是HeapObject的内存结构

1.3 swift_showAlloc

Swift底层探索(二)Swift类和对象的底层分析

// Apple malloc is always 16-byte aligned.
#  define MALLOC_ALIGN_MASK 15

阐明:

  • 经过swift_slowAlloc用来分配内存空间
  • 这儿会经过对齐位数来判别运用哪种办法来分配空间
  • 最小的对齐位数是16字节,假如传入的位数小于16字节,那么便是用16字节对齐,也便是运用malloc办法
  • 假如大于16字节位数,那么运用AlignedAlloc办法

1.4 检查HeapObject结构体

结构体

Swift底层探索(二)Swift类和对象的底层分析

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 目标内存大小核算

Swift底层探索(二)Swift类和对象的底层分析

阐明:

  1. metadata占8个字节
  2. refCounts占8个字节
  3. 再加上age的8个字节
  4. name占8个字节
  5. 所以总共是40个字节

1.6 总结

  1. 实例目标的底层结构是HeapObject结构体
  2. 默许16字节内存大小,metadata 8字节 + refCounts 8字节
    1. metadata是类信息结构,下面会分析
    2. refCounts是引证计数,后边也会详细分析
  3. 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

代码:

Swift底层探索(二)Swift类和对象的底层分析

阐明:

  • 在TargetMetaData中能够看到有一个Kind特点,这是在构建目标时传入的那个参数

检查MetadataKind

Swift底层探索(二)Swift类和对象的底层分析

阐明:

  • 能够看到它是uint32_t类型

类型

Swift底层探索(二)Swift类和对象的底层分析

阐明:

  • 进入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类型

验证:

Swift底层探索(二)Swift类和对象的底层分析

指令:

  • 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

代码:

Swift底层探索(二)Swift类和对象的底层分析

阐明:

  • TargetAnyClassMetadata是一切的类结构,不单单是给Swift用的
  • 承继自TargetHeapMetadata,这也证明类自身也是目标
  • 供给有isa、superclass、cache、data,和OC的底层类结构彻底相同