Redis 中 SDS 相比 C 字符串有哪些优势?

本贴最后更新于 3281 天前,其中的信息可能已经斗转星移

SDS 是什么鬼?

其实,SDS 是 Redis 中实现的一种数据结构,主要用来存储字符串。那 SDS 与 C 字符串相比有什么优势呢?那就看看下面小编为大家的分享吧。

1、常数复杂度获取字符串长度

常规 C 字符串并不记录自身的长度信息,所以为了获取一个 C 字符串的长度,程序必须遍历整个字符串,对遇到的每个字符进行计数,直到遇到代表字符串结尾的空字符为止,这个操作的复杂度为 O(N)。

而 SDS 使用结构体实现,结构体中的 len 属性直接记录了该 SDS 结构体中 buf 数组中已使用的长度,因此获取字符串长度时,只需要获取 len 属性的值,这个操作的复杂度为 O(1)。SDS 结构体的实现确保了获取字符串长度的工作不会成为 Redis 的性能瓶颈。

2、杜绝缓冲区溢出

因为,C 字符串不记录自身的长度,所以当进行字符串复制的时候,如果分配内存不够,就有可能产生缓冲区溢出。

而在 Redis 中,当 SDS API 需要对 SDS 进行修改时,API 会先检查 SDS 的空间是否满足修改所需的要求,如果不满足的话,API 会自动将 SDS 的空间扩展至执行修改所需的大小,然后才执行实际的修改操作。所以,使用 SDS 既不需要手动修改 SDS 的空间大小,也不会出现前面所说的缓冲区溢出问题。

Redis 中 strcat 的实现代码:

sds sdscat(sds s, const char *t) {

return sdscatlen(s, t, strlen(t));

}

sds sdscat(sdss,constchar*t){

returnsdscatlen(s,t,strlen(t));

}

Redis 中 sdscatlen 的实现代码:

sds sdscatlen(sds s, const void *t, size_t len) {

struct sdshdr *sh;

// 原有字符串长度 直接获取len属性

size_t curlen = sdslen(s);

// 扩展 sds 空间

// T = O(N)

s = sdsMakeRoomFor(s,len);

// 内存不足?直接返回

if (s == NULL) return NULL;

// 复制 t 中的内容到字符串后部

// T = O(N)

sh = (void*) (s-(sizeof(struct sdshdr)));

memcpy(s+curlen, t, len);

// 更新属性

sh->len = curlen+len;

sh->free = sh->free-len;

// 添加新结尾符号

s[curlen+len] = '\0';

// 返回新 sds

return s;

}

sds sdscatlen(sdss,constvoid*t,size_tlen){

structsdshdr*sh;

// 原有字符串长度 直接获取 len 属性

size_tcurlen=sdslen(s);

// 扩展 sds 空间

// T = O(N)

s=sdsMakeRoomFor(s,len);

// 内存不足?直接返回

if(s==NULL)returnNULL;

// 复制 t 中的内容到字符串后部

// T = O(N)

sh=(void*)(s-(sizeof(structsdshdr)));

memcpy(s+curlen,t,len);

// 更新属性

sh->len=curlen+len;

sh->free=sh->free-len;

// 添加新结尾符号

s[curlen+len]='\0';

// 返回新 sds

returns;

}

3、减少修改字符串时带来的内存重分配次数

常规 C 字符串,在执行拼接操作或者截断操作时,通常会对数组进行内存重分配,而内存重分配操作涉及复杂的算法,并且可能执行系统调用,所以它通常是一个比较耗时的操作。

Redis 作为数据库,会对数据进行频繁的修改,并且对速度要求极为严苛,所以每次修改字符串长度都需要进行内存重分配,这会对性能造成极大的影响。

为此,Redis 的 SDS 实现了空间预分配和惰性空间释放两种优化策略。

  1. 空间预分配

当 SDS 的 API 对一个 SDS 进行修改时,程序不仅会为 SDS 分配必须要的空间,还会为 SDS 分配额外的未使用空间。

额外分配未使用空间数量的规则:

当 SDS 的 len 属性值小于 1MB,程序分配和 len 属性同样大小的未使用空间。

当 SDS 的 len 属性值大于 1MB,程序将多分配 1M 的未使用空间。

通过这种预分配策略,SDS 将连续增长 N 次字符串所需的内存重分配次数从必定 N 次降低为最多 N 次。

  1. 惰性空间释放

当对 SDS 进行字符串缩短操作时,SDS 的 API 不会立即使用内存重分配回收多出来的字节,而是使用 free 属性将这些字节的数量记录起来,等待将来使用。

当然,SDS 也提供了相应的 API,可以用来真正释放 SDS 的未使用空间,所以不用担心惰性空间释放策略会造成内存浪费。

以上就是 redis 中,SDS 简单动态字符串相比 C 字符串的一些好的地方,个人还是比较实用的,希望对大家有帮助吧。

相关文章:《PHP 开发常用的 8 款 Laravel 软件包》 http://www.maiziedu.com/group/article/663/

  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 74 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 18 关注
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 223 关注
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    939 引用 • 940 回帖
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖 • 1 关注
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 31 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    497 引用 • 1387 回帖 • 294 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    19 引用 • 31 回帖
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    209 引用 • 358 回帖
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 586 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 53 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 733 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    124 引用 • 580 回帖
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    90 引用 • 899 回帖
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 60 关注
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 632 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 2 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    54 引用 • 292 回帖
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    22019 引用 • 87804 回帖 • 2 关注
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖 • 1 关注
  • 创业

    你比 99% 的人都优秀么?

    84 引用 • 1399 回帖 • 1 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 621 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 366 关注
  • OnlyOffice
    4 引用 • 2 关注
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 19 关注
  • 反馈

    Communication channel for makers and users.

    123 引用 • 911 回帖 • 237 关注