Swift 类和结构体底层探究

总结

结构体是值类型,存放在栈空间中
类是引用类型,指针存放在栈空间,指向堆空间。


针对 64bit 环境:
在 Point 中 一个 Int 占8个字节
0x90000 指针在栈中占用8个字节,指向 Size 在堆中的地址,占用32个字节,其中前2个8字节有特殊的用处,第一个存放指向类型的信息,第二个是引用计数。

结构体是值类型

值类型赋值给 var、let或者给函数传参,是直接将所有的内容拷贝一份。
类似于对文件进行copy,产生了全新的文件副本。属于深拷贝。


从反编译的结果来看,p2 = p1 实际上是开辟了新的内存地址,证实是深拷贝,所以修改 p2 的值不会影响 p1。

类是引用类型

引用赋值给 var let 或者给函数传参,是将内存地址拷贝一份
类似于制作一个文件的替身(快捷方式、链接),指向的是同一个文件。属于浅拷贝。

对象的堆空间申请过程

在MAC、iOS中的malloc函数分配的内存大小总是16的倍数

在Swift中,创建类的实例对象,要向堆控件申请内存,大概流程如下:
Class.__allocating_init()
libswiftCore.dylib: \_swift_allocObject
libswiftCore.dylib: swift_slowAlloc
libsystem_malloc.dylib: malloc

通过class_getInstanceSize可以得知:类的对象至少需要占用多少内存

赋值过程

找到初始化函数,返回值一般存于 rax 中,类的初始化方法返回值应为申请堆空间的地址


register read rax 找到堆空间地址,在 View Memery 中查看内存分配情况


第1个8位存的是指向类型信息,第2个8位存的是引用计数信息,之后2个8位存的是初始值10,11

之后找立即数12,13 也就是找$0xc,$0xd



能看出分别是存于 rax+0x10 和 rax+0x18,能推出分别对应 s2.width、s2.height,均是 rax 为地址的第一位,所以得出结论 s1 和 s2存的是同一份地址。

值与引用类型的 let

p = Point(x:3, y:4)
p.x = 10 p.y = 10

  • 错误的原因为 p 是值类型,p 的内存占16个字节,存储 x,y
    let 代表这16个字节的内容无法变更。

s = Size(20, 21)

  • 错误的原因为 s 是引用类型常量,存储的是指向堆空间的指针
    let 代表这个指针无法变更。

s.width = 20 s.height = 20

  • 正确的原因是,修改的是指针所指向的堆空间内容,可以变更
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容