窥探数组的内存
-
我们知道Swift中的数组是结构体,也就是值类型,那么数组的内存究竟是什么样子呢,会不会像自定义的结构体一样,把数据存放到栈空间呢?
Swift中的数组是结构体.png
-
- 我们定义一个数组,先来看看这个变量占用了多少个字节的空间,我们打印了一下,发现arr变量占用了8个字节,这8个字节明显存储不了40个字节的数据,我们来看看这8个字节究竟存储了什么?
var arr = [7,9,6,3,8]
print(MemoryLayout.stride(ofValue: arr)) 打印出来是8个字节
- 我们来看看这段代码的汇编,为了摒除干扰,把打印的代码注释掉,只留下了
var arr = [7,9,6,3,8]
,汇编如下所示
- 我们来看看这段代码的汇编,为了摒除干扰,把打印的代码注释掉,只留下了
TestSwift`main:
0x100001380 <+0>: pushq %rbp
0x100001381 <+1>: movq %rsp, %rbp
0x100001384 <+4>: subq $0x10, %rsp
0x100001388 <+8>: movq 0x4ce1(%rip), %rax ; (void *)0x00007fff8feeaa88: type metadata for Swift.Int
-> 0x10000138f <+15>: movl $0x5, %ecx
0x100001394 <+20>: movl %edi, -0x4(%rbp)
0x100001397 <+23>: movq %rcx, %rdi
0x10000139a <+26>: movq %rsi, -0x10(%rbp)
0x10000139e <+30>: movq %rax, %rsi
0x1000013a1 <+33>: callq 0x10000548a ; symbol stub for: Swift._allocateUninitializedArray<A>(Builtin.Word) -> (Swift.Array<A>, Builtin.RawPointer)
0x1000013a6 <+38>: movq 0x4cc3(%rip), %rsi ; (void *)0x00007fff8feeaa88: type metadata for Swift.Int
0x1000013ad <+45>: movq $0x7, (%rdx)
0x1000013b4 <+52>: movq $0x9, 0x8(%rdx)
0x1000013bc <+60>: movq $0x6, 0x10(%rdx)
0x1000013c4 <+68>: movq $0x3, 0x18(%rdx)
0x1000013cc <+76>: movq $0x8, 0x20(%rdx)
0x1000013d4 <+84>: movq %rax, %rdi
0x1000013d7 <+87>: callq 0x100005436 ; symbol stub for: Swift.Array.init(arrayLiteral: A...) -> Swift.Array<A>
0x1000013dc <+92>: xorl %r8d, %r8d
0x1000013df <+95>: movq %rax, 0x5e02(%rip) ; TestSwift.arr : Swift.Array<Swift.Int>
0x1000013e6 <+102>: movl %r8d, %eax
0x1000013e9 <+105>: addq $0x10, %rsp
0x1000013ed <+109>: popq %rbp
0x1000013ee <+110>: retq
- 重点看这一句
movq %rax, 0x5e02(%rip) ; TestSwift.arr : Swift.Array<Swift.Int>
,从注释可以看出来arr变量存储的数据就是rax寄存器的值
,如下所示,打印出来是0x00000001034000f0
,熟悉内存的朋友,很容易就可以看出来,这个地址是堆空间的地址
- 重点看这一句
(lldb) register read rax
rax = 0x00000001034000f0
- 我们利用LLDB命令
x/10xg 0x00000001034000f0
,来看看这个堆空间地址,到底存储了什么,如下所示,打印出来,发现我们的数据[7,9,6,3,8]
,就在这个堆空间第33个字节往后的位置
- 我们利用LLDB命令
(lldb) x/10xg 0x00000001034000f0
0x1034000f0: 0x00007fff9cc33260 0x0000000000000002
0x103400100: 0x0000000000000005 0x000000000000000a
0x103400110: 0x0000000000000007 0x0000000000000009
0x103400120: 0x0000000000000006 0x0000000000000003
0x103400130: 0x0000000000000008 0x0000000000000000
-
我没有搞清楚前8个字节的作用,但是后面的字节,通过多次改变数组大小,查看堆空间后,我大致可以猜到了,第二组8个字节存放的应该是引用计数,第三组8个字节是数组的元素数量,第四组应该是数组的容量,再往后的字节,才是我们存储的数据,如下所示
数组的内存
-
- 从上述分析,我们就可以知道,数组看起来是结构体+值类型,本质上还是引用类型,只不过我们可以按照结构体的用法来使用
网友评论