欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Swift类和对象的底层探索分析,

来源: 开发者 投稿于  被查看 25313 次 评论:34

Swift类和对象的底层探索分析,


目录
  • 引言
  • 1. 对象
    • 1.1 上层代码中查找
      • 1.1.1 查找对象调用方法
      • 1.1.2 设置符号断点
    • 1.2 swift_allocObject
      • 1.3 swift_showAlloc
        • 1.4 查看HeapObject结构体
          • 1.5 对象内存大小计算
            • 1.6 总结
            • 2. 类
              • 2.1 查找HeapMetadata
                • 2.2. TargetHeapMetaData
                  • 2.3. TargetMetaData
                    • 2.4. TargetClassMetadata
                      • 2.5. TargetAnyClassMetadata

                      引言

                      在上文已经了解了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的底层类结构完全一样

                      以上就是Swift类和对象的底层探索分析的详细内容,更多关于Swift类和对象的资料请关注3672js教程其它相关文章!

                      您可能感兴趣的文章:
                      • Swift 字符串类型及常用方法详解总结
                      • Swift 5.1 之类型转换与模式匹配的教程详解
                      • Swift如何使用类型擦除及自定义详解
                      • 详解Swift面向对象编程中的方法(method)
                      • 解析Swift语言面相对象编程中的继承特性

                      用户评论