日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Swift類和對象的底層探索分析_Swift

作者:文乙 ? 更新時間: 2022-10-28 編程語言

引言

在上文已經了解了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的底層類結構完全一樣

原文鏈接:https://juejin.cn/post/7138028713316188167

欄目分類
最近更新