Swift 内存管理简介4

230 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情

二、内存管理

swift中使⽤⾃动引⽤计数(ARC)机制来追踪和管理内存。

class ZGTeacher {
    var age: Int = 18
    var name: String = "Zhang"
}

var t = ZGTeacher()
///固定写法,打印这个t实例的内存指针
print(Unmanaged.passUnretained(t as AnyObject).toOpaque())
print("end")

打印输出

0x0000000101252a90

我们用x/8g指令输出一下

(lldb) x/8g 0x0000000101252a90
0x101252a90: 0x0000000100008198 0x0000000000000003
0x101252aa0: 0x0000000000000012 0x000000676e61685a
0x101252ab0: 0xe500000000000000 0x0000000000000000
0x101252ac0: 0x00000009a0080001 0x00007ff84be59aa0

我们拿到了这个实例对象t的内存指针地址,我们知道实例对象内存地址其中的前**16个字节的后8个字节在这个过程当中本质上是存储我们的refCounts**,但我们不知道它存储的到底代表什么意思,现在我们在Swift源码里面看一下。

首先我们先找到**refCount的定义,这里我们在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 *__ptrauth_objc_isa_pointer 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)
   { }

我们看到refCounts是由InlineRefCounts定义的,接下来,我们沿着这个InlineRefCounts定义点击进去。

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

可以看到InlineRefCounts其实是一个模版类,接受一个泛型参数InlineRefCountBits

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

   // Out-of-line slow paths.

   SWIFT_NOINLINE
   void incrementSlow(RefCountBits oldbits, uint32_t inc) SWIFT_CC(PreserveMost);

   SWIFT_NOINLINE
   void incrementNonAtomicSlow(RefCountBits oldbits, uint32_t inc);

   SWIFT_NOINLINE
   bool tryIncrementSlow(RefCountBits oldbits);

   ......
   }

可以看到,本质上它在操作我们的API的时候都操作的是我们的泛型参数**RefCountBitsInlineRefCountBits它其实是一个模版类,RefCounts本质上是对我们当前引用计数的一个包装,我们引用计数的具体类型取决于传进来的参数RefCountBits**。

// Basic encoding of refcount and flag data into the object's header.
 template <RefCountInlinedness refcountIsInline>
 class RefCountBitsT {

   friend class RefCountBitsT<RefCountIsInline>;
   friend class RefCountBitsT<RefCountNotInline>;
   
   static const RefCountInlinedness Inlinedness = refcountIsInline;

   typedef typename RefCountBitsInt<refcountIsInline, sizeof(void*)>::Type
     BitsType;
   typedef typename RefCountBitsInt<refcountIsInline, sizeof(void*)>::SignedType
     SignedBitsType;
   typedef RefCountBitOffsets<sizeof(BitsType)>
     Offsets;

   BitsType bits;

点击Type看一下类型,它是一个uint64_t类型的位域信息

template <>
 struct RefCountBitsInt<RefCountNotInline, 4> {
   typedef uint64_t Type;
   typedef int64_t SignedType;
 };

看到这里我们可以得出结论,我们的引用计数它是一个64位的位域信息。在这个位域信息里存储了和我们当前这个运行生命周期相关的引用计数。
当我们创建一个实例对象的时候,当前的引用计数是多少?
我们先从源代码中找一下它的初始化方法new (object) HeapObject(metadata)

static HeapObject *_swift_allocObject_(HeapMetadata const *metadata,
                                       size_t requiredSize,
                                       size_t requiredAlignmentMask) {
  assert(isAlignmentMask(requiredAlignmentMask));
  auto object = reinterpret_cast<HeapObject *>(
      swift_slowAlloc(requiredSize, requiredAlignmentMask));

  // NOTE: this relies on the C++17 guaranteed semantics of no null-pointer
  // check on the placement new allocator which we have observed on Windows,
  // Linux, and macOS.
  new (object) HeapObject(metadata);

  // If leak tracking is enabled, start tracking this object.
  SWIFT_LEAKS_START_TRACKING_OBJECT(object);

  SWIFT_RT_TRACK_INVOCATION(object, swift_allocObject);

  return object;
}

点击HeapObject方法,我们看到了它的初始化赋值方法refCounts(InlineRefCounts::Initialized)

// Initialize a HeapObject header as appropriate for a newly-allocated object.
  constexpr HeapObject(HeapMetadata const *newMetadata) 
    : metadata(newMetadata)
    , refCounts(InlineRefCounts::Initialized)
  { }

点击或者搜索Initialized,可以看到以下代码:

public:
  enum Initialized_t { Initialized };
  enum Immortal_t { Immortal };

  // RefCounts must be trivially constructible to avoid ObjC++
  // destruction overhead at runtime. Use RefCounts(Initialized)
  // to produce an initialized instance.
  RefCounts() = default;
  
  // Refcount of a new object is 1.
  constexpr RefCounts(Initialized_t)
    : refCounts(RefCountBits(0, 1)) {}

  // Refcount of an immortal object has top and bottom bits set
  constexpr RefCounts(Immortal_t)
  : refCounts(RefCountBits(RefCountBits::Immortal)) {}
  

RefCountBits就是我们刚才讲的模版类。想要了解这个类那么我们就去搜索一下RefCountBitsT

SWIFT_ALWAYS_INLINE
  constexpr
  RefCountBitsT(uint32_t strongExtraCount, uint32_t unownedCount)
    : bits((BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift) |
           (BitsType(1)                << Offsets::PureSwiftDeallocShift) |
           (BitsType(unownedCount)     << Offsets::UnownedRefCountShift))
  { }

strongExtraCount 传入的0,StrongExtraRefCountShift 在33位,unownedCount 传入的是1,UnownedRefCountShift 1位, 0左移33位是0,1左移1位是2。