「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」
通过上一篇文章针对类的SIL文件的分析,我们已经了解了在Swift中对象进行内存分配的流程,接下来我们继续分析对象的内存结构;
Swift对象内存结构
HeapObject
Swift对象的内存结构是HeapObject(OC对象的内存结构为objc_object);其定义如下:
其有两个属性:
MetadataRefCounts:默认占用16字节大小;根据HeapObject的定义可知:metadata占用8字节;SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS占用8字节;refCounts:是一个64位的位域信息;
Swift对象默认占用16字节,OC对象默认占用8字节;
那么HeapMetadata的内存结构是什么样子呢?
HeapMetadata
从Swift源码中我们可以找到:
HeapMetadata是TargetHeapMetadata这个类型的别名定义。
TargetHeapMetadata
其定义如下:
TargetHeapMetadata继承自TargetMetadata;
从其定义可以分析得知:如果该类是一个纯Swift类,那么其类型为MetadataKind,如果该类需要与objc交互,那么它就是我们OC中常见的isa;
MetadataKind
MetadataKind定义如下:
该类中没有相关信息,我们需要分析
TargetHeapMetadata的父类TargetMetadata;
TargetMetadata
该类定义代码有些长,未截取!从代码可以分析出:TargetMetadata的Kind为StoredPointer类型。在该类中有函数getTypeContextDescriptor:
在该函数中通过
getKind返回的类型来区分当前类的类型;而TargetClassMetadata就是所有类型元类的最终基类;
如果是Class,那么将会把当前指针this通过static_cast强转为TargetClassMetadata类型;
TargetClassMetadata
TargetClassMetadata继承自TargetAnyClassMetadata;
TargetAnyClassMetadata
从TargetAnyClassMetadata的数据结构中我们发现,其结构中含有Superclass,CacheData[2],Data等属性,这与OC类的结构很相似;
总结
从而我们可以分析得到如下的数据结构:
struct Metadata{
var kind: Int
var superClass: Any.Type
var cacheData: (Int, Int)
var data: Int
var classFlags: Int32
var instanceAddressPoint: UInt32
var instanceSize: UInt32
var instanceAlignmentMask: UInt16
var reserved: UInt16
var classSize: UInt32
var classAddressPoint: UInt32
var typeDescriptor: UnsafeMutableRawPointer
var iVarDestroyer: UnsafeRawPointer
}
该数据结构,极有可能就是我们Swift类的数据结构;
接下来我们验证此数据结构,我们将此结构体绑定为类的指针类型;
我们前面已经分析得到Swift的内存结构是HeapObject,其内部含有metadata和64位的refCounts,那么我们来创建一个结构体如下:
将
64位的refCounts分为两个32位的refCount;HeapObject就是我们当前对象的实例结构;
那么变量t存储的内存地址应该就是指向结构体HeapObject,那么我们就可以将t指针重新绑定位HeapObject结构体类型:
可以看到
metadata和refCount1中有值,refCount1为何为3后续再讲解;
同样的,我们可以将metadata还原成Metadata的结构体类型,代码如下: