swift底层探索 01 - 类初始化&类结构swift底层探索 01 - 类初始化&类结构

2021-08-09 11:28:13 浏览数 (1)

探索swift可以通过:源码调试Sil文件xcode断点调试这些方式来进行探索,除Sil文件这种方式其他的都会在本文中出现。OC底层探索01-找到底层探索的钥匙会有解释。

探索路径同样是参考oc的探索路径,先从类开始。

类初始化

1. 使用Xcodel断点调试
  • 创建一个简单的类,开启汇编断点
  • 1步骤就是__allocation_initswift对象初始化入口
  • 通过2步骤可以进入下一步(下断点,按住control ↓)
  • swift_allocObject是初始化第二步
  • 下断点,按住control ↓进入下一步
  • swift_slowAlloc是初始化第三步
  • 下断点,按住control ↓进入下一步
  • malloc_zone_malloc是初始化第四步,在这一步完成内存的分配,最终完成alloc步骤
2. 使用源码调试

现在通过源码调试来验证一下之前的论点。源码编译方式Swift-5.3.1 源码编译.

代码语言:javascript复制
static HeapObject *_swift_allocObject_(HeapMetadata const *metadata,
                                       size_t requiredSize,
                                       size_t requiredAlignmentMask) {
  assert(isAlignmentMask(requiredAlignmentMask));
  //swift慢速创建流程
  auto object = reinterpret_cast<HeapObject *>(
      swift_slowAlloc(requiredSize, requiredAlignmentMask));
  //为创建好的内存赋值
  new (object) HeapObject(metadata);

  SWIFT_LEAKS_START_TRACKING_OBJECT(object);

  SWIFT_RT_TRACK_INVOCATION(object, swift_allocObject);

  return object;
}

void *swift::swift_slowAlloc(size_t size, size_t alignMask) {
  void *p;
  
  //一般使用 8字节对齐 
  //#  define MALLOC_ALIGN_MASK 15
  if (alignMask <= MALLOC_ALIGN_MASK) {
#if defined(__APPLE__)
    //apple的类会进入这里
    p = malloc_zone_malloc(DEFAULT_ZONE(), size);
#else
    p = malloc(size);
#endif
  } else {
  //大于16字节对齐的情况,比较少见
    size_t alignment = (alignMask == ~(size_t(0)))
                           ? _swift_MinAllocationAlignment
                           : alignMask   1;
    p = AlignedAlloc(size, alignment);
  }
  if (!p) swift::crash("Could not allocate memory.");
  return p;
}
  • 根据源码也可以跟到具体的流程
  • alignMask <= MALLOC_ALIGN_MASK进入这个判断可以看出swift类一般使用的是8字节对齐
代码语言:javascript复制
#define malloc_zone_malloc(zone,size) malloc(size)
  • malloc_zone_malloc只是一个宏定义,最终调用malloc
3. 初始化流程图

类结构 - HeapObject结构

1. 编译器断点
  • 在进行类创建,源码调试的时候发现swift的类结构是这样的。和oc比起来是有一些不同的。我们换种方式看看.
2. lldb
  • 相比于OC不同的是,除了第一位之外,还将引用计数当做第二个参数保存到对象中
3. 源码查看

swift对象继承自**HeapObject**

代码语言:javascript复制
struct HeapObject {
  /// This is always a valid pointer to a metadata object.
  HeapMetadata const *metadata;

//#define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       
  InlineRefCounts refCounts
  SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
  
  ...
}
swift-类的结构图

HeapMetadata结构

如果说metaData相比于oc对象中的isa的而言的话,应该要包含isa,superclass,cache_t,date等类的信息。我们就来看看HeapMetadata结构都有些什么呢~

代码语言:javascript复制
//相当于宏定义 
using HeapMetadata = TargetHeapMetadata<InProcess>

//template 模板类
struct TargetHeapMetadata : TargetMetadata<InProcess>{
    。。。
}

struct TargetMetadata<InProcess>{
    StoredPointer Kind; //用来区分是什么类型的原数据 

//一个相关的方法
    getObjCClassObject() const {
    return reinterpret_cast<Class>(
      const_cast<TargetClassMetadata<InProcess>*>(
        getClassObject()));
  }
}
  • TargetHeapMetadata是一个模板类,想要了解内部结构需要继续向下查看
  • <InProcess>类似于泛型,限制泛型的具体类型
  • 没有看到其他相关定义,只能借助其他方式来查看getClassObject
借助getClassObject方法查看HeapMetadata结构
代码语言:javascript复制
//获取类对象
  Metadata::getClassObject() const {
    switch (getKind()) {
    case MetadataKind::Class: {
      return static_cast<const ClassMetadata *>(this);
    }
    //如果是类,指针强转为ClassMetadata
    case MetadataKind::ObjCClassWrapper: {
      auto wrapper = static_cast<const ObjCClassWrapperMetadata *>(this);
      return wrapper->Class;
    }
      return nullptr;
    }
  }
  • 我们发现将当前指针强转为ClassMetadata。指针可以强转则表示内部结构是相同的,我们可以转换角度去查看ClassMetadata.
ClassMetadata
代码语言:javascript复制
using ClassMetadata = TargetClassMetadata<InProcess>;
struct TargetClassMetadata : TargetAnyClassMetadata<Runtime> {
    ClassFlags Flags;
    uint32_t InstanceAddressPoint;
    uint32_t InstanceSize;
    ...
}

struct TargetAnyClassMetadata : TargetHeapMetadata
{
  ConstTargetMetadataPointer  Superclass;
  TargetPointer CacheData[2];
  StoredSize Data;
  ...
}
  • 看到这部分应该是明白了,结构和OC底层探索08-基于objc4-781类结构分析是相同的。
  • 只有kind有点不一致,其实也可以看做是isa,都是指向元类
元类结构图

swift类结构.png

0 人点赞