Swift实例对象内存结构 - ShenYj/ShenYj.github.io GitHub Wiki

Swift实例对象内存结构

HeapObject

Swift 对象结构本质也是一个结构体 HeapObject

  • HeapObject.h源码中关于HeapObject 结构体的定义

    struct HeapObject {
    /// This is always a valid pointer to a metadata object.
    HeapMetadata const *metadata;
    
    SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
    
    #ifndef __swift__
    HeapObject() = default;
    
    // Initialize a HeapObject header as appropriate for a newly-allocated object.
    constexpr HeapObject(HeapMetadata const *newMetadata) 
        : metadata(newMetadata)
        , refCounts(InlineRefCounts::Initialized)
    { }
    
    // Initialize a HeapObject header for an immortal object
    constexpr HeapObject(HeapMetadata const *newMetadata,
                        InlineRefCounts::Immortal_t immortal)
    : metadata(newMetadata)
    , refCounts(InlineRefCounts::Immortal)
    { }
    
    #ifndef NDEBUG
    void dump() const LLVM_ATTRIBUTE_USED;
    #endif
    
    #endif // __swift__
    };

    c/c++ 的代码最多的就是这种类型定义和别名,我是跳来跳去翻了好久

    • SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS 到底是个啥

      • 首先得知存在一个InlineRefCounts refCounts 类型的成员变量

        #define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS InlineRefCounts refCounts
      • InlineRefCounts又是个别名

        typedef RefCounts<InlineRefCountBits> InlineRefCounts;

        目前掌握的信息:

      • RefCounts是个模板类, 运行期取决 RefCountBits的一个类型参数,从上一步得知,这个模板参数类型为InlineRefCountBits

        template <typename RefCountBits>
        class RefCounts {
            std::atomic<RefCountBits> refCounts;
            ...
        }
      • 而这里的 InlineRefCountBits 又是个别名

        typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;

        其实这里还有一处定义 typedef RefCounts<SideTableRefCountBits> SideTableRefCounts;
        再网上查询到的资料描述是: 模板参数 RefCountBits 指定了真实的内部类型,在 Swift ABI 里总共有两种:前者是用在 HeapObject 中的,而后者是用在 HeapObjectSideTableEntry(Side Table)中的一般来讲,Swift 对象并不会用到 Side Table,一旦对象被 weak 或 unowned 引用,该对象就会分配一个 Side Table。

        • RefCountIsInline是一个 enum类型

          // RefCountIsInline: refcount stored in an object
          // RefCountNotInline: refcount stored in an object's side table entry
          enum RefCountInlinedness { RefCountNotInline = false, RefCountIsInline = true };
        • RefCountBitsT是个模板类, 并且有个关键的成员变量 bits (省略其他代码)

          class RefCountBitsT {
          
              typedef typename RefCountBitsInt<refcountIsInline, sizeof(void*)>::Type BitsType;
              BitsType bits;
          
              ...
          }
        • 根据 BitsType 别名的定义: 将 RefCountBitsInt 这个结构体中的Type 起别名为 BitsType

          // 64-bit inline
          // 64-bit out of line
          template <RefCountInlinedness refcountIsInline>
          struct RefCountBitsInt<refcountIsInline, 8> {
          typedef uint64_t Type;
          typedef int64_t SignedType;
          };

      最终得到这个 bits类型就是 uint64_t

包含两个成员

  • HeapMetadata const *metadata; 8字节 (等同于OC里面的类对象)
  • SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS; 8字节 (引用计数)

两个指针类型,初始默认大小: 16字节

示例

class Person {
    var age: Int = 1         // 8  字节
    var name: String = "abc" // 16 字节, Swift 中 String 也是结构体类型
}
print(MemoryLayout<Int>.size)  -> 8
print(MemoryLayout<String>.size) -> 16
  • HeapObject (metadata 8字节 (等同于OC里面的类对象), reCount 8字节 (引用计数)) 默认16字节大小
  • 加上两个属性, 占用内存大小: 8 + 8 + 8 + 16 => 40字节

对比 Object-C

Swift Object-C
底层 objc_class -> objc_object HeapObject
Size大小 metadata, refCounts 大于16字节 isa,superclass,cache,bits 大于32字节

这里的大小是两根指针的占用空间, 在探究Swift的 MetaData 继承关系后可见 Swift的内存结构设计了很多的成员变量, 比如从TargetClassMetadata中继承了大部分的成员变量

HeapObject 源码学习

⚠️ **GitHub.com Fallback** ⚠️