一.瞅瞅String是个啥
stirng是个结构体
@frozen public struct String
二.做1个测试
var str1: String = "0123456789"
print(MemoryLayout.stride(ofValue: str1)) //16
let ptr1 = withUnsafeMutablePointer(to: &str1) {$0} //0x000000016da55ad0
看一下ptr1的内容
再看一下ASCII表
发现0x000000016da55ad0里面直接存储了0123456789这几个字符。
8-16位0xea00000000003938
多出来了一个0xea
,我们看下那是什么
- e 代表类型标识, 即该字符串是直接存储了内容信息
- a等于十进制的10, 代表这个字符串占用了10个字节。
总结:
这种简单字符串,最多能存储15个字节内容,剩下一个字节用来描述字符串的类型。和OC的tagPointer技术非常一样。
三.再做1个测试
var str2: String = "0123456789ABCEDF"
print(MemoryLayout.stride(ofValue: str2)) //16
let ptr2 = withUnsafeMutablePointer(to: &str2) {$0} //0x000000016ba39ad0
看看超过15个字节的字符串, 内部已经不直接存储字符串的具体内容了
看看汇编吧
如果小于16,就跳转到其他函数
x0 = 0x0000000104071370 "0123456789ABCEDF" = 字符串的真实地址
x1 = 0x0000000000000010 = 十进制的16 = 字符串的长度
x2 = 0x0000000000000001
字符串的真正位置: 代码段
总结:大于16位的字符串,一般占用16个字节。
- 0xd000000000010 d是个一个标志位,10代表字符串的长度
- 0x80000001043d9350: 减去#0x7fffffffffffffe0 = 0x1043D9370, 即字符串真正的地址
四.append的情况
注意:只要是swfit的字符串,其内容都处于TEXT_cstring中。
注意:str1和str2是个指针,在栈区
- 当小于16位的字符串,使用类似oc的tagPointer技术,将字符串从test段读取到栈指针里面。如果append其他字符,只要不超过16,就继续添加。
- 当大于16位的字符串,如果append则会在堆空间创建新的字符串,然后栈指针的第8-16位指向新的空间。