Swift 中的类

Swift 中,类对象的结构是否和 Objective-C 一样呢?

SwiftObject

在swift中,如果没有明确声明父类的类,则会隐式地继承自 SwiftObject (支持与 Objective-C 混编的前提下,因为 SwiftObject 是一个 Objective-C 类),隐式继承来源于 swiftABI/TypeLayout.rst 文档。

关于 SwiftObject 的定义如下:

#if SWIFT_OBJC_INTEROP
#if __OBJC__

// Source code: "SwiftObject"
// Real class name: mangled "Swift._SwiftObject"
#define SwiftObject _TtCs12_SwiftObject

#if __has_attribute(objc_root_class)
__attribute__((__objc_root_class__))
#endif
SWIFT_RUNTIME_EXPORT @interface SwiftObject<NSObject> {
 @private
  Class isa;
  SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
}

...
  
@end

namespace swift {

id getDescription(OpaqueValue *value, const Metadata *type);

}

#endif
#endif

namespace swift {

/// Get the NSObject metadata.
const Metadata *getNSObjectMetadata();

}

#endif

SwiftObject 的声明是 SWIFT_OBJC_INTEROPtrue 的情况下才有声明的,而在苹果平台下,都是支持 swiftObjective-C 进行混编的,因此 SWIFT_OBJC_INTEROP1(true)SWIFT_OBJC_INTEROP 宏的定义可在 Config.h 中找到

/// Does the current Swift platform support "unbridged" interoperation
/// with Objective-C?  If so, the implementations of various types must
/// implicitly handle Objective-C pointers.
///
/// Apple platforms support this by default.
#ifndef SWIFT_OBJC_INTEROP
#ifdef __APPLE__
#define SWIFT_OBJC_INTEROP 1
#else
#define SWIFT_OBJC_INTEROP 0
#endif
#endif

SwiftObject 的定义中可以看到

  • 第一个成员变量和 Objective-C 一样是 isa 指针,暂时猜想和 Objective-C 中的 isa 指针功能一样
  • 第二个成员变量是一个 SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS 宏,其定义可在 HeapObject.hRefCount.h 中找到,从命名上看是引用计数器
// RefCount.h
// This definition is a placeholder for importing into Swift.
// It provides size and alignment but cannot be manipulated safely there.
typedef struct {
  __swift_uintptr_t refCounts SWIFT_ATTRIBUTE_UNAVAILABLE;
} InlineRefCountsPlaceholder;

#if defined(__swift__)

typedef InlineRefCountsPlaceholder InlineRefCounts;

#else

// HeapObject.h
namespace swift {

struct InProcess;

template <typename Target> struct TargetHeapMetadata;
using HeapMetadata = TargetHeapMetadata<InProcess>;
#else
typedef struct HeapMetadata HeapMetadata;
typedef struct HeapObject HeapObject;
#endif

// The members of the HeapObject header that are not shared by a
// standard Objective-C instance
#define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
  InlineRefCounts refCounts

/// The Swift heap-object header.
/// This must match RefCountedStructTy in IRGen.
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__
};

在下文的所有测试代码中,均使用自定义 Person

class Person {
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    func printData() {
        print("name=\(name), age=\(age)")
    }
}

验证父类

下面通过2种方式来验证在 swift 中,没有明确声明父类的类,会隐式继承 SwiftObject

  • Objective-C runtime
print(class_getSuperclass(Person.self))

打印结果为:

Optional(_TtCs12_SwiftObject)
  • MachO文件
Person Superclass

_$s11ClassStruct6PersonCN 这个结构体可以理解为 Person 类的类对象,其 superclass 指针指向 _TtCs12_SwiftObject

_TtCs12_SwiftObjectSwiftObject 的真实类名,可在 SwiftObject.h 的文档中找到相关的描述:

// Source code: "SwiftObject"
// Real class name: mangled "Swift._SwiftObject"
#define SwiftObject _TtCs12_SwiftObject

HeapObject

swift 中,基本上分配在堆上的对象都是一个 HeapObject。其定义可在 HeapObject.h 中找到:

// The members of the HeapObject header that are not shared by a
// standard Objective-C instance
#define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
  InlineRefCounts refCounts

/// The Swift heap-object header.
/// This must match RefCountedStructTy in IRGen.
struct HeapObject {
  /// This is always a valid pointer to a metadata object.
  HeapMetadata const *metadata;

  SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;

  ...
};

metadata 是指向类结构 HeapMetadata 的指针,refCounts 所包含的信息比较多,使用了掩码,其中包含了引用计数。

因此 Person 的实例对象的成员变量是在偏移量为16个字节开始,前16个字节分别存放 metadata 的指针和 refCounts 的引用计数,Person 的实例对象对应的内存结构可以对应如下的结构体:

struct PersonStruct {
    // 指向类对象的指针
    let metaData: UnsafePointer
    let refCounts: __uint64_t
    var name: String
    let age: Int
}

定义一个简单的 person 实例对象,并定义一个结构体 personStruct 指向 person 内存,并修改 personStruct 结构体的 name 属性和 age 属性,看 person 对象的属性是否有对应的修改

var person = Person(name: "swift", age: 6)
// 将指向person对象内存地址的指针转成指向PersonStruct结构体的指针,实则还是指向同一个内存地址
var pStructPointer = Unmanaged.passUnretained(person).toOpaque().bindMemory(to: PersonStruct.self, capacity: personSize)
print(pStructPointer)

pStructPointer.pointee.name = "struct"
pStructPointer.pointee.age = 1
person.printData()
// 打印结果为:name=struct, age=1

这里需要注意的是,不能把指向 person 实例对象内存地址的指针转成 PersonStruct 结构体,再修改结构体的属性值。

var pStruct = Unmanaged.passUnretained(person).toOpaque().bindMemory(to: PersonStruct.self, capacity: personSize).pointee

这种写法是不会改变 person 对象的属性,因为结构体是值类型,相当于把 person 内存的值都拷贝了一份

HeapMetadata

HeapMetadata 可理解为 Objective-C 中的类对象和元类对象,其对应的结构可在 Metadata.h 中找到

/// In-process native runtime target.
///
/// For interactions in the runtime, this should be the equivalent of working
/// with a plain old pointer type.
struct InProcess {
  static constexpr size_t PointerSize = sizeof(uintptr_t);
  using StoredPointer = uintptr_t;
  using StoredSignedPointer = uintptr_t;
  using StoredSize = size_t;
  using StoredPointerDifference = ptrdiff_t;

  static_assert(sizeof(StoredSize) == sizeof(StoredPointerDifference),
                "target uses differently-sized size_t and ptrdiff_t");
  
  template <typename T>
  using Pointer = T*;

  template <typename T>
  using SignedPointer = T;
  
  ...
};

/// The common structure of all type metadata.
template <typename Runtime>
struct TargetMetadata {
  using StoredPointer = typename Runtime::StoredPointer;

  /// The basic header type.
  typedef TargetTypeMetadataHeader<Runtime> HeaderType;

  ...
    
private:
  /// The kind. Only valid for non-class metadata; getKind() must be used to get
  /// the kind value.
  StoredPointer Kind;
public:
  /// Get the metadata kind.
  MetadataKind getKind() const {
    return getEnumeratedMetadataKind(Kind);
  }
  
  /// Set the metadata kind.
  void setKind(MetadataKind kind) {
    Kind = static_cast<StoredPointer>(kind);
  }

#if SWIFT_OBJC_INTEROP
protected:
  const TargetAnyClassMetadata<Runtime> *getClassISA() const {
    return reinterpret_cast<const TargetAnyClassMetadata<Runtime> *>(Kind);
  }
  void setClassISA(const TargetAnyClassMetadata<Runtime> *isa) {
    Kind = reinterpret_cast<StoredPointer>(isa);
  }
#endif

public:
  /// Is this a class object--the metadata record for a Swift class (which also
  /// serves as the class object), or the class object for an ObjC class (which
  /// is not metadata)?
  bool isClassObject() const {
    return static_cast<MetadataKind>(getKind()) == MetadataKind::Class;
  }
  
  ...
};

/// The common structure of all metadata for heap-allocated types.  A
/// pointer to one of these can be retrieved by loading the 'isa'
/// field of any heap object, whether it was managed by Swift or by
/// Objective-C.  However, when loading from an Objective-C object,
/// this metadata may not have the heap-metadata header, and it may
/// not be the Swift type metadata for the object's dynamic type.
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
};
using HeapMetadata = TargetHeapMetadata<InProcess>;

上面看起来可能还是有点乱,可以看看下面只保留成员变量的结构体

struct TargetMetadata {
  uintptr_t Kind;
}

struct TargetHeapMetadata : TargetMetadata<Runtime> {
  
};

这么一看,结构体中只有一个成员变量 Kind,其实 Kind 属性为 MetadataKind 类型,记录着此 metadata 的实际类型,其定义在 MetadataValues.h & MetadataKind.def 中能找到:

/// Non-type metadata kinds have this bit set.
const unsigned MetadataKindIsNonType = 0x400;

/// Non-heap metadata kinds have this bit set.
const unsigned MetadataKindIsNonHeap = 0x200;

// The above two flags are negative because the "class" kind has to be zero,
// and class metadata is both type and heap metadata.

/// Runtime-private metadata has this bit set. The compiler must not statically
/// generate metadata objects with these kinds, and external tools should not
/// rely on the stability of these values or the precise binary layout of
/// their associated data structures.
const unsigned MetadataKindIsRuntimePrivate = 0x100;

/// Kinds of Swift metadata records.  Some of these are types, some
/// aren't.
enum class MetadataKind : uint32_t {
#define METADATAKIND(name, value) name = value,
#define ABSTRACTMETADATAKIND(name, start, end)                                 \
  name##_Start = start, name##_End = end,
#include "MetadataKind.def"
  /// ABSTRACTMETADATAKIND(Name, Start, End)
///   Represents an abstraction categorization of a range of metadata kind
///   values. Name is the identifier of the range and Start, End are the
///   beginning and end of the range.
#ifndef ABSTRACTMETADATAKIND
#define ABSTRACTMETADATAKIND(Name, Start, End)
#endif

/// NOMINALTYPEMETADATAKIND(Name, Value)
///   Represents the native metadata kind for a swift nominal type. Name is the
///   name of the kind and Value is the integral value used to identify the
///   value. Delegates to METADATAKIND if not defined.
#ifndef NOMINALTYPEMETADATAKIND
#define NOMINALTYPEMETADATAKIND(Name, Value) METADATAKIND(Name, Value)
#endif

/// A class type.
NOMINALTYPEMETADATAKIND(Class, 0)

/// A struct type.
NOMINALTYPEMETADATAKIND(Struct, 0 | MetadataKindIsNonHeap)

/// An enum type.
/// If we add reference enums, that needs to go here.
NOMINALTYPEMETADATAKIND(Enum, 1 | MetadataKindIsNonHeap)

/// An optional type.
NOMINALTYPEMETADATAKIND(Optional, 2 | MetadataKindIsNonHeap)

/// A foreign class, such as a Core Foundation class.
METADATAKIND(ForeignClass, 3 | MetadataKindIsNonHeap)

/// A type whose value is not exposed in the metadata system.
METADATAKIND(Opaque, 0 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// A tuple.
METADATAKIND(Tuple, 1 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// A monomorphic function.
METADATAKIND(Function, 2 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// An existential type.
METADATAKIND(Existential, 3 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// A metatype.
METADATAKIND(Metatype, 4 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// An ObjC class wrapper.
METADATAKIND(ObjCClassWrapper, 5 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// An existential metatype.
METADATAKIND(ExistentialMetatype, 6 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)

/// A heap-allocated local variable using statically-generated metadata.
METADATAKIND(HeapLocalVariable, 0 | MetadataKindIsNonType)

/// A heap-allocated local variable using runtime-instantiated metadata.
METADATAKIND(HeapGenericLocalVariable,
             0 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)

/// A native error object.
METADATAKIND(ErrorObject,
             1 | MetadataKindIsNonType | MetadataKindIsRuntimePrivate)
  
  LastEnumerated = 0x7FF,
};

可能不太好看,MetadataKind 是枚举类型,其值如下表格:

name Value
Class 0x0
Struct 0x200
Enum 0x201
Optional 0x202
ForeignClass 0x203
Opaque 0x300
Tuple 0x301
Function 0x302
Existential 0x303
Metatype 0x304
ObjCClassWrapper 0x305
ExistentialMetatype 0x306
HeapLocalVariable 0x400
HeapGenericLocalVariable 0x500
ErrorObject 0x501
LastEnumerated 0x7FF

TargetMetadata 结构体中有个函数可以获取其类型

struct TargetMetadata {
  ...
    
private:
  /// The kind. Only valid for non-class metadata; getKind() must be used to get
  /// the kind value.
  StoredPointer Kind;
public:
  /// Get the metadata kind.
  MetadataKind getKind() const {
    return getEnumeratedMetadataKind(Kind);
  }
  
  /// Set the metadata kind.
  void setKind(MetadataKind kind) {
    Kind = static_cast<StoredPointer>(kind);
  }
  ...
}

/// Try to translate the 'isa' value of a type/heap metadata into a value
/// of the MetadataKind enum.
inline MetadataKind getEnumeratedMetadataKind(uint64_t kind) {
  if (kind > LastEnumeratedMetadataKind)
    return MetadataKind::Class;
  return MetadataKind(kind);
}

如果 kind 大于 0x7FF 的话,都为 MetadataKind::Class 类型。下面可以看看 Person 类的 Kind

print(String(format: "0x%02lx", Unmanaged.passUnretained(person).toOpaque().load(as: __uint64_t.self)))
// 打印结果:0x1000092d8

也可以通过 LLDB 来获取其值:

Person Kind

因此 getEnumeratedMetadataKind(uint64_t kind) 返回 MetadataKind::Class

/// Get the nominal type descriptor if this metadata describes a nominal type,
/// or return null if it does not.
ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>
getTypeContextDescriptor() const {
    switch (getKind()) {
  case MetadataKind::Class: {
      const auto cls = static_cast<const TargetClassMetadata<Runtime> *>(this);
    if (!cls->isTypeMetadata())
        return nullptr;
    if (cls->isArtificialSubclass())
        return nullptr;
    return cls->getDescription();
    }
    case MetadataKind::Struct:
    case MetadataKind::Enum:
    case MetadataKind::Optional:
    return static_cast<const TargetValueMetadata<Runtime> *>(this)
          ->Description;
    case MetadataKind::ForeignClass:
    return static_cast<const TargetForeignClassMetadata<Runtime> *>(this)
          ->Description;
    default:
    return nullptr;
    }
}

在函数 getTypeContextDescriptor() 中可以看到,如果 Kind 类型为 MetadataKind::Class 的话,可以转成 TargetClassMetadata 结构体

/// The structure of all class metadata.  This structure is embedded
/// directly within the class's heap metadata structure and therefore
/// cannot be extended without an ABI break.
///
/// Note that the layout of this type is compatible with the layout of
/// an Objective-C class.
template <typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  using StoredSize = typename Runtime::StoredSize;

  // The remaining fields are valid only when isTypeMetadata().
  // The Objective-C runtime knows the offsets to some of these fields.
  // Be careful when accessing them.

  /// Swift-specific class flags.
  ClassFlags Flags;

  /// The address point of instances of this type.
  uint32_t InstanceAddressPoint;

  /// The required size of instances of this type.
  /// 'InstanceAddressPoint' bytes go before the address point;
  /// 'InstanceSize - InstanceAddressPoint' bytes go after it.
  uint32_t InstanceSize;

  /// The alignment mask of the address point of instances of this type.
  uint16_t InstanceAlignMask;

  /// Reserved for runtime use.
  uint16_t Reserved;

  /// The total size of the class object, including prefix and suffix
  /// extents.
  uint32_t ClassSize;

  /// The offset of the address point within the class object.
  uint32_t ClassAddressPoint;

  // Description is by far the most likely field for a client to try
  // to access directly, so we force access to go through accessors.
private:
  /// An out-of-line Swift-specific description of the type, or null
  /// if this is an artificial subclass.  We currently provide no
  /// supported mechanism for making a non-artificial subclass
  /// dynamically.
  TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;

public:
  /// A function for destroying instance variables, used to clean up after an
  /// early return from a constructor. If null, no clean up will be performed
  /// and all ivars must be trivial.
  TargetSignedPointer<Runtime, ClassIVarDestroyer * __ptrauth_swift_heap_object_destructor> IVarDestroyer;
  
  ...
};
using ClassMetadata = TargetClassMetadata<InProcess>;

/// The portion of a class metadata object that is compatible with
/// all classes, even non-Swift ones.
template <typename Runtime>
struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  using StoredSize = typename Runtime::StoredSize;

#if SWIFT_OBJC_INTEROP
  // Allow setting the metadata kind to a class ISA on class metadata.
  using TargetMetadata<Runtime>::getClassISA;
  using TargetMetadata<Runtime>::setClassISA;
#endif

  // Note that ObjC classes does not have a metadata header.

  /// The metadata for the superclass.  This is null for the root class.
  ConstTargetMetadataPointer<Runtime, swift::TargetClassMetadata> Superclass;

  // TODO: remove the CacheData and Data fields in non-ObjC-interop builds.

  /// The cache data is used for certain dynamic lookups; it is owned
  /// by the runtime and generally needs to interoperate with
  /// Objective-C's use.
  TargetPointer<Runtime, void> CacheData[2];

  /// The data pointer is used for out-of-line metadata and is
  /// generally opaque, except that the compiler sets the low bit in
  /// order to indicate that this is a Swift metatype and therefore
  /// that the type metadata header is present.
  StoredSize Data;
};
using AnyClassMetadata =
  TargetAnyClassMetadata<InProcess>;

接下来通过验证一下,可以定义如下 C++ 结构体:

struct TargetAnyClassMetadata {
    struct TargetAnyClassMetadata* Kind;
    void* superClass;
    void* CacheData[2];
    void* Data;
};

struct TargetClassMetadata {
    uintptr_t Kind;  
    struct AnyClassHeapMetadata* superClass;
    void* CacheData[2];
    void* Data;
  
    uint32_t Flags;
    uint32_t InstanceAddressPoint;
    uint32_t InstanceSize;
    uint16_t InstanceAlignMask;
    uint16_t Reserved;
    uint32_t ClassSize;
    uint32_t ClassAddressPoint;
    uintptr_t Description;
    uintptr_t IVarDestroyer;
};

打印 TargetClassMetadata 中的 InstanceSize 的值,即为 Person 类创建的实例对象所占的内存大小

let personMetaData = pStructPointer.pointee.metaData.bindMemory(to: TargetClassMetadata.self, capacity: MemoryLayout<TargetClassMetadata>.stride).pointee
print(personMetaData.InstanceSize)
// 打印结果为:40

Person 中,name 属性占用16字节,age 属性占用8字节,隐式继承的 SwiftObject 的成员变量 metadata 指针和 refCounts 分别都占用 8字节,加起来总共占用40个字节用于存放成员变量,但由于内存对齐,实际分配的内存为48字节

print("person对象占用的内存大小: \(malloc_size(pPointer))")
// 打印结果为:person对象占用的内存大小: 48

我们可以继续获取其 Kind 值所指向的“元类对象”,可理解为 Objective-C 中的元类对象。下面可以打印 Person 的类对象和元类对象的地址:

/// 类对象地址指针
let clsAddress = pStructPointer.pointee.metaData
/// Person元类对象地址
let metaAddress = String(format: "0x%02lx", personMetaData.Kind)
print("Person类对象地址: \(clsAddress)")
print("Person元类对象地址: \(metaAddress)")

打印结果为:

Person类对象地址: 0x10000a2d8
Person元类对象地址: 0x10000a2a0

使用 Hopper Disassembler 查看MachO 文件

MachO

⚠️:不能通过 Objective-C 的运行时来获取 Swift 类的类对象和元类对象,通过 objc_getClass()objc_getMetaClass() 这些 Objective-C 运行时runtime 方法获取到的类对象和元类对象是动态创建出来的,不可取

RefCount 引用计数

实例对象的第二个成员变量 refCounts 从名字上看是存放引用计数,但并不是直接存放的,而且采用了掩码进行存放,类似于 Objective-C 中的 isa 指针,其定义可在 RefCount.h 中找到

// 64-bit inline
// 64-bit out of line
// 32-bit out of line
template <>
struct RefCountBitOffsets<8> {
  /*
   The bottom 32 bits (on 64 bit architectures, fewer on 32 bit) of the refcount
   field are effectively a union of two different configurations:
   
   ---Normal case---
   Bit 0: Does this object need to call out to the ObjC runtime for deallocation
   Bits 1-31: Unowned refcount
   
   ---Immortal case---
   All bits set, the object does not deallocate or have a refcount
   */
  static const size_t PureSwiftDeallocShift = 0;
  static const size_t PureSwiftDeallocBitCount = 1;
  static const uint64_t PureSwiftDeallocMask = maskForField(PureSwiftDealloc);

  static const size_t UnownedRefCountShift = shiftAfterField(PureSwiftDealloc);
  static const size_t UnownedRefCountBitCount = 31;
  static const uint64_t UnownedRefCountMask = maskForField(UnownedRefCount);

  static const size_t IsImmortalShift = 0; // overlaps PureSwiftDealloc and UnownedRefCount
  static const size_t IsImmortalBitCount = 32;
  static const uint64_t IsImmortalMask = maskForField(IsImmortal);

  static const size_t IsDeinitingShift = shiftAfterField(UnownedRefCount);
  static const size_t IsDeinitingBitCount = 1;
  static const uint64_t IsDeinitingMask = maskForField(IsDeiniting);

  static const size_t StrongExtraRefCountShift = shiftAfterField(IsDeiniting);
  static const size_t StrongExtraRefCountBitCount = 30;
  static const uint64_t StrongExtraRefCountMask = maskForField(StrongExtraRefCount);
  
  static const size_t UseSlowRCShift = shiftAfterField(StrongExtraRefCount);
  static const size_t UseSlowRCBitCount = 1;
  static const uint64_t UseSlowRCMask = maskForField(UseSlowRC);

  static const size_t SideTableShift = 0;
  static const size_t SideTableBitCount = 62;
  static const uint64_t SideTableMask = maskForField(SideTable);
  static const size_t SideTableUnusedLowBits = 3;

  static const size_t SideTableMarkShift = SideTableBitCount;
  static const size_t SideTableMarkBitCount = 1;
  static const uint64_t SideTableMarkMask = maskForField(SideTableMark);
};

typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;

template <typename RefCountBits>
class RefCounts {
  std::atomic<RefCountBits> refCounts;

    ...
};

typedef RefCounts<InlineRefCountBits> InlineRefCounts;
typedef RefCounts<SideTableRefCountBits> SideTableRefCounts;

掩码对应的值如下表所示:

掩码名称 掩码起始位置 位数
PureSwiftDeallocShift 0x1UL<<0 1
UnownedRefCountShift 0x1UL<<1 31
IsImmortalShift 0x1UL<<0 32
IsDeinitingShift 0x1UL<<32 1
StrongExtraRefCountShift 0x1UL<<33 30
UseSlowRCShift 0x1UL<<63 1
SideTableShift 0x1UL<<0 62
SideTableMarkShift 0x1UL<<62 1
RefCountBits

通过代码验证一下 UnownedRefCountShiftStrongExtraRefCountShift

let p1 = Person(name: "swift", age: 6)
let p2 = p1
let p3 = p1
unowned let p4 = p1
unowned let p5 = p1

上面有3个强引用,2个无主引用(总数为2+1,初始值为1),接下来获取 p1 对象的 refCounts 值:

person RefCounts

0x0000000600000006 中对应强引用计数 StrongExtraRefCountShift 的值为 0x3,对应无主引用计数 UnownedRefCountShift 的值为0x3

若对象存在弱引用,其弱引用计数在 sidetable 中的

weak var p6 = p1
Weak RefCounts

其值已发生改变,SideTableMarkShift 标志位为 1。

Person 内存图解

我自己画了一幅图来描述 Person 的内存结构:

Memory Layout

⚠️:Person 元类对象不是TargetClassMetadata类型的,Person 类对象才是

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342