底层是 SDS,动态字符串
而 SDS 在 RedisObject 中对应三大物理编码:
- int
- embstr
- raw
int:
如果存储的字符串是整数值,并且大小在 LONG_MAX 范围内,则会采用 INT 编码:直接将数据保存在 RedisObject 的 ptr 指针位置(刚好8字节),不再需要 SDS 了。
像这样
emdstr:
如果存储的 SDS 长度小于44字节,则会采用 EMBSTR 编码,此时 object head 与 SDS 是一段连续空间。申请内存时只需要调用一次内存分配函数,效率更高。
像这样
为什么是 44 字节,因为 redisObject 占 16 个字节,SDS 前三个字段占 3 个,字符数组结尾的 \0 占一个,所以字符串的长度为44
这样可以组成 64 字节大小的内存片段,因为 redis 做内存分配的时候会议 2^N 去分配,这样不易产生内存碎片
raw:
保存长度大于44字节的字符串
证明
实现
一个 SDS 由四个字段构成,前三个字段各占 1 个字节
- len:已用的字节长度
- alloc:字符串的最大字节长度
- flags:用来表示 SDS 的类型
- buf[]:真正有效的字符串数据,长度由 alloc 控制
sds.h
有多种大小的 SDS,大部分情况我们使用 8 位都足够了,256 字节以下的长度
字符串扩容机制:
如果新字符串小于1M,则新空间为扩展后字符串长度的两倍+1;
如果新字符串大于1M,则新空间为扩展后字符串长度+1M+1。称为内存预分配。
为什么 SDS
C 语言靠自己的 char[] 来实现。
为什么:
- 获取字符串长度的需要通过运算
- 非二进制安全
- 不可修改
字符串在 C 语言中的存储方式,想要获取「Redis」的长度,需要从头开始遍历,直到遇到 '\O' 为止。所以,Redis 没有直接使用C语言传统的字符串标识,而是自己构建了一种名为简单动态字符串 SDS(simple dynamic string)的抽象类型,并将 SDS 作为 Redis 的默认字符串。