在 Swift 中,类对象的结构是否和 Objective-C 一样呢?
SwiftObject
在swift中,如果没有明确声明父类的类,则会隐式地继承自 SwiftObject (支持与 Objective-C 混编的前提下,因为 SwiftObject 是一个 Objective-C 类),隐式继承来源于 swift 的 ABI/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_INTEROP
为 true
的情况下才有声明的,而在苹果平台下,都是支持 swift 与 Objective-C 进行混编的,因此 SWIFT_OBJC_INTEROP
为 1(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.h 和 RefCount.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文件
_$s11ClassStruct6PersonCN 这个结构体可以理解为 Person
类的类对象,其 superclass
指针指向 _TtCs12_SwiftObject
_TtCs12_SwiftObject 是 SwiftObject 的真实类名,可在 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 来获取其值:
因此 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 文件
⚠️:不能通过 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 |
通过代码验证一下 UnownedRefCountShift
和 StrongExtraRefCountShift
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
值:
0x0000000600000006 中对应强引用计数 StrongExtraRefCountShift
的值为 0x3,对应无主引用计数 UnownedRefCountShift
的值为0x3
若对象存在弱引用,其弱引用计数在 sidetable 中的
weak var p6 = p1
其值已发生改变,SideTableMarkShift
标志位为 1。
Person 内存图解
我自己画了一幅图来描述 Person
的内存结构:
⚠️:
Person
元类对象不是TargetClassMetadata类型的,Person
类对象才是