Swift 对象数据结构

359 阅读3分钟

Swift对象内存分配

Swift 对象内存分配: 

  • __allocating_init -----> swift_allocObject ---- - swift_allocObject ----->  swift_slowAlloc -----> Malloc
  • Swift 对象的内存结构 HeapObject (OC objc_object) ,有两个属性:  一个是Metadata ,一个是 RefCount ,默认占用 16 字节大小。

经过源码分析我们不难得出 swift 类的数据结构

struct Metadatavar kind: Int 
    var superClass: Any.Type 
    var cacheData: (Int, Intvar data: Int 
    var classFlags: Int32 
    var instanceAddressPoint: UInt32 
    var instanceSize: UInt32 
    var instanceAlignmentMask: UInt16 
    var reserved: UInt16 
    var classSize: UInt32 
    var classAddressPoint: UInt32 
    var typeDescriptor: UnsafeMutableRawPointer 
    var iVarDestroyer: UnsafeRawPointer
}

这里我们有一个东西需要关注 typeDescriptor ,不管是 Class , Struct , Enum 都有自己 的 Descriptor ,就是对类的一个详细描述

struct TargetClassDescriptorvar flags: UInt32 
    var parent: UInt32 
    var name: Int32 
    var accessFunctionPointer: Int32 
    var fieldDescriptor: Int32 
    var superClassType: Int32 
    var metadataNegativeSizeInWords: UInt32 
    var metadataPositiveSizeInWords: UInt32 
    var numImmediateMembers: UInt32 
    var numFields: UInt32 
    var fieldOffsetVectorOffset: UInt32 
    var Offset: UInt32 
    var size: UInt32 
    //V-Table
}

Mahco: Mach-O 其实是Mach Object文件格式的缩写,是 mac 以及 iOS 上可执行文件的格式, 类似于 windows 上的 PE 格式 (Portable Executable ), linux 上的 elf 格式 (Executable and Linking Format) 。常见的 .o,.a .dylib Framework,dyld .dsym。  Mahoc文件格式:

Swift第二节课:类与结构体(下)_3_1.jpg

  • 首先是文件头,表明该文件是 Mach-O 格式,指定目标架构,还有一些其他的文件属性信息,文件头信息影响后续的文件结构安排
  • Load commands是一张包含很多内容的表。内容包括区域的位置、符号表、动态符号表等。
LC_SEGMENT_64将文件中(32位或64位)的段映射到进程地址空间中
LC_DYLD_INFO_ONLY动态链接相关信息
LC_DYSYMTAB动态符号表地址 
LC_LOAD_DYLINKERdyld加载
LC_UUID文件的UUID
LC_VERSION_MIN_MACOSX支持最低的操作系统版本
LC_SOURCE_VERSION源代码版本
LC_MAIN设置程序主线程的入口地址和栈大小
LC_LOAD_DYLIB依赖库的路径,包含三方库 
LC_FUNCTION_STARTS函数起始地址表
LC_CODE_SIGNATURE代码签名
  • Data 区主要就是负责代码和数据记录的。Mach-O 是以 Segment 这种结构来组织数据的,一个 Segment 可以包含 0 个或多个 Section。根据 Segment 是映射的哪一个 LoadCommand,Segment 中 section 就可以被解读为是是代码,常量或者一些其他的数据类型。在装载在内存中时,也是根据 Segment 做内存映射的。

方法调度方式总结:

类型调度方式extension
值类型静态派发静态派发
函数表派发静态派发
NSObject子类函数表派发静态派发

影响函数派发方式

  •  final: 添加了 final 关键字的函数无法被重写,使用静态派发,不会在 vtable 中出现,且对 objc 运行时不可见。 
  •  dynamic: 函数均可添加 dynamic 关键字,为非objc类和值类型的函数赋予动态性,但派发方式还是函数表派发。 
  • @objc: 该关键字可以将Swift函数暴露给Objc运行时,依旧是函数表派发。 
  •  @objc + dynamic: 消息派发的方式

函数内联

函数内联 是一种编译器优化技术,它通过使用方法的内容替换直接调用该方法,从而优  化性能。 

  • 将确保有时内联函数。这是默认行为,我们无需执行任何操作. Swift 编译器可能会自动内联函数作为优化。 
  • always - 将确保始终内联函数。通过在函数前添加 @inline(__always)来实现此行为 
  • never - 将确保永远不会内联函数。这可以通过在函数前添加 @inline(never) 来实现。 
  • 如果函数很长并且想避免增加代码段大小,请使用@inline(never)(使用@inline(never))