面试题:Redis的SDS和C中字符串相比有什么优势?

JAVA herman 93浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:codedq,发送下载链接帮助你免费下载!
本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:codedq,之前的微信号好友位已满,备注:返现
饿了么大量招人,我内推!Java 方向!薪资不设上限,工作年龄不限!工作地点限魔都,可电话面试!简历,发我微信:codedq
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

众所周知,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

看了前面的定义,笔者画了个图:

Redis 简单动态数组 SDS 结构

从图中可以知道 sds 本质分为三部分:header、buf、null 结尾符,其中 header 可以认为是整个 sds 的指引部分,给定了使用的空间大小、最大分配大小等信息,再用一张网上的图来清晰看下 sdshdr8 的实例:

Redis sds 实例

在 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 字符串与 C 字符串的区别

以上,希望大家都能够找到诚心如意的好工作!

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号1:xmtxtt(5000人已满),微信号2:xttblog(5000人已满),微信号3:codedq(超3800)。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!

本文原文出处:业余草: » 面试题:Redis的SDS和C中字符串相比有什么优势?