探究Swift的String底层实现
问题: Swift中的字符串在内存中是如何存储的?
- 首先我们来代码验证一下最简单的字符串--"空字符串"的内存分布
var empty = "" print("empty \(empty)") print(withUnsafePointer(to: &empty, { $0 }))
打印结果:
1. 查看Swift.String
源码链接, 搜索"empty"
- 看关键代码发现底部的
public init
方法调用了内部的init
方法, 该初始化方法接收了一个_StringGuts
的对象作为入参. - 源码
357
行开始, 也可看到结构体String
持有_StringGuts
作为成员变量. 我们继续深挖StringGuts
.
2. 查看StringGuts.swift
源码链接, 搜索"empty".
- 从
_StringGuts
结构体的初始化方法中, 可以看到该结构体持有StringObject
作为成员变量, 拨云见日, 深挖"StringObject".
3. 查看StringObject
源码链接, 搜索"empty".
-
在
StringObject
的init(count: variant: discirminator: flags:)
方法中可以看到StringObject
结构体的4个成员变量. -
在创建一个字符串的过程中, 都存储了什么内容呢?
-
从上面的源码可以看到
String
结构体在底层存储的就是以上4个成员变量的内容. -
初始化方法中
discriminator
成员变量对应的的Nibbles
又是什么呢? - 可以看到
Nibbles
也是一个枚举类型, 但是这里只是定义, 原始定义是:
- 可以看到, 这里调用的方法判断是如果当前是ASCII码, 那么当前的Discriminator判别器就是
0xE000_0000_0000_0000
, 如果不是ASCII码就是0xA000_0000_0000_0000
- 查看一个空字符串的内存分布, 打印结果如下:
- 查看一个包含中文的字符串, 打印结果如下:
-
⭐️综上, 我们可以看出A, E在这里是用来标识当前是否是ASCII码, 其中后面的数字是用来代表当前的多少个字符串的长度.
-
_discriminator
占据4位, 每一位的标识如下:
- 大字符串的规则和
Nibbles
的布局结构如下:
- 对于原生的Swift字符串来说, 采取的是
tail-allocated
(尾递归)存储, 也就是在当前实例分配有超出其最后存储属性的额外空间, 额外的空间可用于直接在实例中存储任意数据, 无需额外的堆分配.代码验证如下:
- 接下来我们需要关注的是
0x8000000100003f60
这个值, 根据上面的源码分析阅读, 我们知道当前0x8
标识的是大字符串
, 这点我们在源码里也可以找到答案:
- 同时结合
nibbles
在内存中的布局我们知道其中b60:b0
是存储字符串的地址, 当然这个地址要加上偏移量, 这个偏移量是32
, 这里我们可通过计算器来验证一下:
下面是ASCII码十六进制符号对照表:
- 那么前面的8个字节是什么呢? 我们可以先从初始化的流程来分析:
- 所以可以看到, 除了我们当前的地址和标识位之外, 剩余的就是
countAndFlags
, 这里我们可以看到布局如下:
- 第一个标志位是
isASCII
, 如果我们修改成中文, 这里就会改变
- ⭐️综上, 我们可以发现Small strings(长度小于等于15的小字符串)直接存在内存中, Large strings(长度大于15的大字符串)存储的是内存地址
回答: Small strings(长度小于等于15的小字符串)直接存在内存中, Large strings(长度大于15的大字符串)存储的是内存地址
发文不易, 喜欢点赞的人更有好运气👍 :), 定期更新+关注不迷路~
ps:欢迎加入笔者18年建立的研究iOS审核及前沿技术的三千人扣群:662339934,坑位有限,备注“掘金网友”可被群管通过~
- iOS老司机聊聊实际项目开发中的<<人月神话>>
- iOS老司机可落地在中大型iOS项目中的5大接地气设计模式合集
- iOS老司机的跨端跨平台Hybrid开发Tips
- iOS老司机的2022年回顾, 聊聊寒冬下的实用<<谈判力>>
- iOS老司机可落地的中大型iOS项目中的设计模式优化Tips_桥接模式
- iOS老司机的多线程PThread学习分享
- iOS老司机整理, iOSer必会的经典算法_2
- iOS老司机的<<蓝海转型>>读书分享
- iOS老司机的<<程序员的自我修养:链接、装载与库>>读书分享
- iOS老司机的接地气算法Tips
- iOS老司机的RunLoop原理探究及实用Tips
- iOS老司机整理, iOSer必会的经典算法_1
- iOS老司机的App启动优化Tips, 让启动速度提升10%
- iOS老司机的网络相关Tips
- 恋上数据结构与算法
- iOS老司机带你一起把App的崩溃率降到0.1%以下
- 探究Swift的String底层实现
- iOS老司机万字整理, 可能是最全的Swift Tips
- iOS老司机可落地的中大型iOS项目中的设计模式优化Tips
- 聊一聊Swift中的闭包