Redis数据结构(读书笔记,持续更新)
第1章、简单动态字符串(SDS)
1.1 SDS与C字符串的区别
C字符串的存储结构与SDS的buf属性一致。
1.1.1 常数复杂度获取字符串长度
- C字符串需要遍历整个字符串,直到遇到代表字符串结尾的空字符串为止,复杂度O(n)。
- SDS的len属性记录了长度,所以获取长度的复杂度为O(1)。
设置和更新SDS长度的工作是由SDS的API在执行时自动完成的,使用者无须手动修改。
1.1.2 杜绝缓冲区溢出
- C字符串不记录自身的长度,如果未给key1分配足够的空间的情况下,执行strcat扩展字符串长度,可能导致key1的数据溢出到其他已占用的空间中,使其他key的数据被修改。
- SDS在修改时,会先判断SDS的空间是否满足修改,不满足会先扩展空间,再执行实际的修改操作。
1.1.3 减少修改字符串带来的内存重分配次数
-
C字符串修改字符串长度N次就要执行N此内存重分配,疏忽时可能会造成内存溢出或泄露。
-
SDS为避免这种缺陷,使用空间预分配和惰性空间释放两种优化策略。
1. 空间预分配
在对空间扩展时,不仅分配修改所需要的空间,还会分配额外的未使用的空间,下次修改时,可以直接使用的话,就不需要重新内存分配。未使用空间的公式:
- 修改之后len属性的值小于1MB时,分配len值同大小的空间。
- 大于1MB时,分配1MB的空间。
2 惰性空间释放
缩短SDS字符串时,释放出来的空间,会作为未使用的空间,不进行内存重分配。
有需要时可以使用相应的API真正释放此空间。
1.1.4 二进制安全
- C字符串防止误认为字符串结尾,不能存空字符的数据,只能保存文本数据,不能保存图片、视频等二进制数据。
- SDS字符串用len属性判断结尾,可以存文本和二进制数据。
1.2 总结
C 字符串 | SDS |
---|---|
获取字符串长度的复杂度O(N) | 获取字符串长度的复杂度O(1) |
API不安全,可能会造成缓冲区溢出 | API安全,不会造成缓冲区溢出 |
修改N次字符串长度必须执行N次内存重分配 | 修改N次字符串长度最多执行N次内存重分配 |
只能保存文本数据 | 可以保存文本或者二进制数据 |