目录

swift-5-汇编分析结构体类的内存布局

swift -(5) 汇编分析结构体、类的内存布局

一、结构体

在 Swift 标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分

比如

Bool

Int

Double

String

Array

Dictionary

等常见类型都是结构体

  struct Date {
         var year: Int
         var month: Int
         var day: Int   }
  var date = Date(year: 2019, month: 6, day: 23)

所有的结构体都有一个编译器自动生成的初始化器( initializer ,初始化方法、构造器、构造方法)

在第⑥行调用的,可以传入所有成员值,用以初始化所有成员(存储属性,Stored

Property

二、结构体的初始化器

编译器会根据情况,可能会为结构体生成多个初始化器,宗旨是:保证所有成员都有初始值

https://i-blog.csdnimg.cn/direct/070c316969a84e83bd04cabbedb12541.png

从这列子中可以看出,编译器最终选择什么初始化器和结构体原始定义有没有赋默认值有关,编译器选择的初始化器会保证所有成员都有初始值;

三、这 能编译通过么

struct Point {  var x: Int? var y: Int?
}
var p1 = Point(x: 10, y: 10)
var p2 = Point(y: 10)
var p3 = Point(x: 10)
var p4 = Point()

根据编译器初使化饿的本质 保证所有成员都有初始值

可选项都有个默认值

nil

因此可以编译通过

四、 自定义初始化器

注: 一旦在定义结构体时自定义了初始化器,编译器就不会再帮它自动生

成其他初始化器

因此下边的代码后边三句会拨错

五、 窥探初始化器的本质分析自定义 初始化器 和编译器会我们生成的 初始化器是一样的么

第一句 编译器的初始化qi
struct Point {
var x: Int = 0 var
y: Int = 0
}
var p = Point()

第二句  自己的初始化qi
struct Point { 
var x: Int 
var y: Int
init() {  
x = 0 
y = 0
   }
}
var p = Point()

通过上面的汇编指令可以看出 编译器自己调用的初始化qi和我们自己写的初始化qi其实是一样的

六、结构体占用内存大小

https://i-blog.csdnimg.cn/direct/cb1846e797f0427d8872bd4eb7bda448.png

七、

类的定义和结构体类似,但编译器并没有为类自动生成可以传

入成员值的初始化器

https://i-blog.csdnimg.cn/direct/6d76b33e003543bf97d3162dc48c998f.png

如何里面的x和y 没有初使值,你调用无参会报错,因为你的对象创建完成后,你里面的x和y成员没有值是不安全的

如果类的所有成员都在定义的时候指定了初始值,编译器会为类生成无

参的初始化器;

成员的初始化是在这个初始化器中完成的

https://i-blog.csdnimg.cn/direct/1908626559514ce5a7a1c8c9dbb5af8a.png

八、 结构体与类的本质区别

结构体是值类型(枚举也是值类型),类是引用类型(指针类型)

https://i-blog.csdnimg.cn/direct/482eed0eb0c94d3193a442c23e35b6f5.png

https://i-blog.csdnimg.cn/direct/7fa8a2c34386482c87f50565a7af3abf.png

九、 值类型 的深拷贝

值类型赋值给

var

let

或者给函数传参,是直接将所有内容拷

贝一份

类似于对文件进行

copy

paste

操作,产生了全新的文件副本。属于深拷贝(

deep

copy

https://i-blog.csdnimg.cn/direct/3ccc3e865b9e4247a409c5923d2d6a6d.png

p2.x = 11 p2.y = 22
// 请问p1.x和p1.y是多少?

依然是原来的1020

十 、 值类型的赋值操作

在Swift标准库中,为了提升性能,

String

Array

Dictionary

Set

采取了Copy On Write的技术

比如仅当有“写”操作时,才会真正执行拷贝操作

对于标准库值类型的赋值操作,

Swift 能确保最佳性能,所有没必要为了保证最佳性能来避免赋值

建议

:不需要修改的,尽量定义成

let

https://i-blog.csdnimg.cn/direct/59ef5690afd64484b3591967db2bb19e.png

为了提升性能,

String

Array

Dictionary

Set

采取了Copy On Write的

var

s1

=

“Jack”

var

s2

=

s1

如有了这句才会有深拷贝,在之前没有发生写操作,直接就是浅拷贝

s2

.

append

(

“_

Rose

"

)

print

(

s1

)

//

Jack

print

(

s2

)

//

Jack_Rose

https://i-blog.csdnimg.cn/direct/05de6bb4499740cab3e312cc90dec71b.png

十一、 引用类型的赋值

https://i-blog.csdnimg.cn/direct/362e8001afa64f658fb1944eabac29d7.png

s2.

width

=

11

s2.

height

=

22

//

请问

s1.width

s1.height

是多少 11 22

十二、堆空间内存占用情况

class Point  {
var x = 11
var test = true 
var y = 22
}
var p = Point()
class_getInstanceSize(type(of: p)) // 40
class_getInstanceSize(Point.self) // 40

内存地址的前16字节存的是p的地址,堆空间会检查是不是16的倍数,对空间内存对其是48
根据内存对其 分配40哥字节,内存地址按8对其,实际用到的是16+8+8+3 =33

总结-汇编内存存值总结 5  1.30

内存地址格式为:0x4bdc(%rip) ,一般是全局变量 ,全局区(数据段)

内存地址格式为:-0x78(%rbp) ,一般是局部变量 ,栈空间

内存地址格式为:0x10(%rax) ,一般是堆空间