Redis 中的字符串是可以修改的字符串,在内存中它是以字节数组的形式存在的。
Redis 的字符串叫「SDS」,也就是 Simple Dynamic String。它的结构是一个带长度信息的字节数组。
struct SDS<T> { T capacity;// 数组容量 T len; // 数组长度 byte flags; // 特殊标识位 byte[] content; // 数组内容 }
capacity 和 len 的区别请看下图:
capacity 表示所分配数组的长度,len 表示字符串的实际长度。content 里面存储了真正的字符串内容。前面我们提到字符串是可以修改的字符串,它要支持 append 操作。如果数组没有冗余空间,那么追加操作必然涉及到分配新数组,然后将旧内容复制过来,再 append 新内容。如果字符串的长度非常长,这样的内存分配和复制开销就会非常大。
SDS 结构使用了范型 T,为什么不直接用 int呢,这是因为当字符串比较短时,len 和 capacity 可以使用 byte 和 short 来表示,Redis 为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示。
Redis 规定字符串的长度不得超过 512M 字节。创建字符串时 len 和 capacity 一样长,不会多分配冗余空间,这是因为绝大多数场景下我们不会使用 append 操作来修改字符串。
Redis 的字符串有两种存储方式,在长度特别短时,使用 emb 形式存储(embeded),当长度超过 44 时,使用 raw 形式存储。
字符串在长度小于 1M 之前,扩容空间采用加倍策略,也就是保留 100% 的冗余空间。当长度超过 1M 之后,为了避免加倍后的冗余空间过大而导致浪费,每次扩容只会多分配 1M 大小的冗余空间。