众所周知,Redis 是现在最火的 nosql 系统。面试必备,面试必会。今年情况特别特殊,困难重重,前段时间群里刮起了一阵学习 Redis 源码的风。刚好最近有网友面试遇到了,Redis 的 SDS 和 C 中字符串相比有什么优势?本文来简单的说一说。
在 C 语言中使用 N + 1 长度的字符数组来表示字符串,尾部使用’/0’作为结尾标志,对于此种实现无法满足 Redis 对于安全性、效率、丰富的功能的要求,因此 Redis 单独封装了 SDS 简单动态字符串结构。
在理解 SDS 的优势之前需要先看下 SDS 的实现细节,找了 github 最新的 src/sds.h 的定义看下:
typedef char *sds;
/*这个用不到 忽略即可*/
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
/*不同长度的header 8 16 32 64共4种 都给出了四个成员
len:当前使用的空间大小;alloc去掉header和结尾空字符的最大空间大小
flags:8位的标记 下面关于SDS_TYPE_x的宏定义只有5种 3bit足够了 5bit没有用
buf:这个跟C语言中的字符数组是一样的,从typedef char* sds可以知道就是这样的。
buf的最大长度是2^n 其中n为sdshdr的类型,如当选择sdshdr16,buf_max=2^16。
*/
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
#define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3
看了前面的定义,笔者画了个图:
从图中可以知道 sds 本质分为三部分:header、buf、null 结尾符,其中 header 可以认为是整个 sds 的指引部分,给定了使用的空间大小、最大分配大小等信息,再用一张网上的图来清晰看下 sdshdr8 的实例:
在 sds.h/sds.c 源码中可清楚地看到sds完整的实现细节,本文就不展开了要不然篇幅就过长了,快速进入主题说下 sds 的优势:
- null
- O(1) 获取长度: C 字符串需要遍历而 sds 中有 len 可以直接获得;
- 防止缓冲区溢出 bufferoverflow: 当 sds 需要对字符串进行修改时,首先借助于 len 和 alloc 检查空间是否满足修改所需的要求,如果空间不够的话,SDS 会自动扩展空间,避免了像 C 字符串操作中的覆盖情况;
- 有效降低内存分配次数:C 字符串在涉及增加或者清除操作时会改变底层数组的大小造成重新分配、sds 使用了空间预分配和惰性空间释放机制,说白了就是每次在扩展时是成倍的多分配的,在缩容是也是先留着并不正式归还给 OS,这两个机制也是比较好理解的;
- 二进制安全:C 语言字符串只能保存 ascii 码,对于图片、音频等信息无法保存,sds 是二进制安全的,写入什么读取就是什么,不做任何过滤和限制;
老规矩上一张黄健宏大神总结好的图:
以上,希望大家都能够找到诚心如意的好工作!
: » 面试题:Redis的SDS和C中字符串相比有什么优势?
原创文章,作者:506227337,如若转载,请注明出处:https://blog.ytso.com/252200.html