简单动态字符串

2023-10-27

Sds (Simple Dynamic String,简单动态字符串)是 Redis 底层所使用的字符串表示, 几乎所有的 Redis 模块中都用了 sds。

常规字符串

在 C 语言中,字符串可以用一个 \0 结尾的 char 数组来表示。

比如说, hello world 在 C 语言中就可以表示为 “hello world\0” 。

存在的问题

这种简单的字符串表示,在大多数情况下都能满足要求,但是,它并不能高效地支持长度计算和追加(append)这两种操作:

SDS用途

Sds 在 Redis 中的主要作用有以下两个:
-实现字符串对象(StringObject);
-在 Redis 程序内部用作 char* 类型的替代品

用 sds 取代 C 默认的 char* 类型
因为 char* 类型的功能单一, 抽象层次低, 并且不能高效地支持一些 Redis 常用的操作(比如追加操作和长度计算操作), 所以在 Redis 程序内部, 绝大部分情况下都会使用 sds 而不是 char* 来表示字符串。

性能问题在稍后介绍 sds 定义的时候就会说到, 因为我们还没有了解过 Redis 的其他功能模块, 所以也没办法详细地举例说那里用到了 sds , 不过在后面的章节中, 我们会经常看到其他模块(几乎每一个)都用到了 sds 类型值。

目前来说, 只要记住这个事实即可: 在 Redis 中, 客户端传入服务器的协议内容、 aof 缓存、 返回给客户端的回复, 等等, 这些重要的内容都是由 sds 类型来保存的。

原因

Redis 中的字符串
在 C 语言中,字符串可以用一个 \0 结尾的 char 数组来表示。

比如说, hello world 在 C 语言中就可以表示为 “hello world\0” 。

这种简单的字符串表示,在大多数情况下都能满足要求,但是,它并不能高效地支持长度计算和追加(append)这两种操作:

每次计算字符串长度(strlen(s))的复杂度为 θ(N) 。
对字符串进行 N 次追加,必定需要对字符串进行 N 次内存重分配(realloc)。
在 Redis 内部, 字符串的追加和长度计算很常见, 而 APPEND 和 STRLEN 更是这两种操作,在 Redis 命令中的直接映射, 这两个简单的操作不应该成为性能的瓶颈。

另外, Redis 除了处理 C 字符串之外, 还需要处理单纯的字节数组, 以及服务器协议等内容, 所以为了方便起见, Redis 的字符串表示还应该是二进制安全的: 程序不应对字符串里面保存的数据做任何假设, 数据可以是以 \0 结尾的 C 字符串, 也可以是单纯的字节数组, 或者其他格式的数据。

考虑到这两个原因, Redis 使用 sds 类型替换了 C 语言的默认字符串表示: sds 既可高效地实现追加和长度计算, 同时是二进制安全的。

Memory Allocation Strategy

动态内存分配,类似于vector, 减少内存的分配次数

也就是说, 当大小小于 1MB 的字符串执行追加操作时, sdsMakeRoomFor 就为它们分配多于所需大小一倍的空间; 当字符串的大小大于 1MB , 那么 sdsMakeRoomFor 就为它们额外多分配 1MB 的空间。

It pre-allocates memory to reduce memory allocation times. Actually, it just simply doubles the original size when it is less than SDS_MAX_PREALLOC(1MB). This is similar to C++ vector allocation strategy when memory is not enough. This is why string append operation does not need to allocate memory every time.

内存释放Destroy

SDS memory (including sds header) is dynamically allocated. So just call free to release memory to system.

动态内存分配带来的缺点

这种分配策略会浪费内存吗?

执行过 APPEND 命令的字符串会带有额外的预分配空间, 这些预分配空间不会被释放, 除非该字符串所对应的键被删除, 或者等到关闭 Redis 之后, 再次启动时重新载入的字符串对象将不会有预分配空间。

因为执行 APPEND 命令的字符串键数量通常并不多, 占用内存的体积通常也不大, 所以这一般并不算什么问题。

另一方面, 如果执行 APPEND 操作的键很多, 而字符串的体积又很大的话, 那可能就需要修改 Redis 服务器, 让它定时释放一些字符串键的预分配空间, 从而更有效地使用内存。

总结

Redis 的字符串表示为 sds ,而不是 C 字符串(以 \0 结尾的 char*)。
对比 C 字符串, sds 有以下特性:

  • 可以高效地执行长度计算(strlen);

  • 可以高效地执行追加操作(append);

  • 二进制安全;
    sds 会为追加操作进行优化:加快追加操作的速度,并降低内存分配的次数,代价是多占用了一些内存,而且这些内存不会被主动释放。

参考一
参考二

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

简单动态字符串 的相关文章

  • 如何统计 Redis 流中未读或已确认的消息?

    使用 Redis 5 0 3 假设我们创建一个名为streamy和一个消费群体consumers XGROUP CREATE streamy consumers MKSTREAM 然后向其中添加一些消息 XADD streamy messa
  • 如果另一个键中的计数器低于零,则从集合中原子删除一个项目?

    雷迪斯2 0 3 在我的 Redis DB 中 我有一组项目 每个项目都有一个与其关联的计数器 MULTI SADD items set foo INCRBY items foo 10000 EXEC 新项目会以随机间隔添加到集合中 当用户
  • Redis INCRBY 有限制

    我想知道是否有一种方法可以通过我的应用程序的单次往返在 Redis 中执行此操作 对于给定的键K 其可能值V是范围内的任意整数 A B 基本上 它有上限和下限 When an INCRBY or DECRBY发出命令 例如INCRBY ke
  • 如何批量删除Redis中数十万个带有特殊字符的key

    我们有一个包含数十万个 Redis 键的列表 其中包含各种特殊字符 我们希望批量删除它们 对于这个问题上的类似问题 有一些很好的答案 如何使用 Redis 自动删除与模式匹配的键 https stackoverflow com questi
  • 使用Redis从有限范围内生成唯一ID

    我有一些数据库项目 除了主键之外 还需要项目所属组的唯一索引 我们来调用属性nbr 以及将项目分组在一起并定义唯一范围的属性nbr 我们会打电话group This nbr必须在 1 N 范围内 并且may从外部源导入项目时进行设置 由于所
  • 2 个具有共享 Redis 依赖的 Helm Chart

    目前 我有 2 个 Helm Charts Chart A 和 Chart B Chart A 和 Chart B 对 Redis 实例具有相同的依赖关系 如Chart yaml file dependencies name redis v
  • Redis是如何实现高吞吐量和高性能的?

    我知道这是一个非常普遍的问题 但是 我想了解允许 Redis 或 MemCached Cassandra 等缓存 以惊人的性能极限工作的主要架构决策是什么 如何维持连接 连接是 TCP 还是 HTTP 我知道它完全是用C写的 内存是如何管理
  • 如何使 Redis 缓存中数据层次结构(树)的部分内容无效

    我有一些产品数据 需要在 Redis 缓存中存储多个版本 数据由 JSON 序列化对象组成 获取普通 基本 数据的过程很昂贵 将其定制为不同版本的过程也很昂贵 因此我想缓存所有版本以尽可能进行优化 数据结构看起来像这样 BaseProduc
  • redis dump.rdb / 保存小文件

    Context 我正在使用redis 数据库小于 100 MB 但是 我想进行每日备份 我也在 Ubuntu Server 12 04 上运行 当输入 redis cli save 我不知道 dump rdb 保存到哪里 因为 redis
  • redis 2.8.7 Linux Sentinel环境配置问题,如何使其自启动,应该订阅什么?

    现在我们尝试使用 redis 2 8 7 作为缓存存储 来自使用 booksleeve 客户端的 NET Web 应用程序 目前看来这是一个非常有趣和令人兴奋的任务 redis 文档非常好 但由于缺乏真正的实践经验 我确实有几个关于如何正确
  • 想要在后台不间断地运行redis-server

    我已经下载了 redis 2 6 16 tar gz 文件并安装成功 安装后我运行 src redis server 它工作正常 但我不想每次都手动运行 src redis server 而是希望 redis server 作为后台进程持续
  • Scala 使用的 Redis 客户端库建议

    我正在计划使用 Scala 中的 Redis 实例进行一些工作 并正在寻找有关使用哪些客户端库的建议 理想情况下 如果存在一个好的库 我希望有一个为 Scala 而不是 Java 设计的库 但如果现在这是更好的方法 那么仅使用 Java 客
  • Redis+Docker+Django - 错误 111 连接被拒绝

    我正在尝试使用 Redis 作为使用 Docker Compose 的 Django 项目的 Celery 代理 我无法弄清楚我到底做错了什么 但尽管控制台日志消息告诉我 Redis 正在运行并接受连接 事实上 当我这样做时 docker
  • Amazon Elasticache Redis 集群 - 无法获取端点

    我需要获取 Amazon Elasticache 中 Redis 集群的终端节点 以下代码适用于 Memcached 集群 但不适用于 Redis import com amazonaws auth AWSCredentials impor
  • 节点应用程序之间共享会话?

    我目前有两个独立的节点应用程序在两个不同的端口上运行 但共享相同的后端数据存储 我需要在两个应用程序之间共享用户会话 以便当用户通过一个应用程序登录时 他们的会话可用 并且他们似乎已登录到另一个应用程序 在本例中 它是一个面向公众的网站和一
  • 如何使用redis发布/订阅

    目前我正在使用node js和redis来构建应用程序 我使用redis的原因是因为发布 订阅功能 该应用程序只是在用户进入用户或离开房间时通知经理 function publishMsg channel mssage redisClien
  • Spring Redis 排序键

    我在 Redis Spring Data Redis 中有以下键 localhost gt Keys 1 id 1 Name C5796 Site DRG1 2 id 2 Name CX1XE Site DG1 3 id 3 Name C5
  • Spring Data Redis 覆盖默认序列化器

    我正在尝试创建一个RedisTemplatebean 将具有更新的值序列化器来序列化对象JSONredis 中的格式 Configuration class RedisConfig Bean name redisTemplate Prima
  • 将文件传递给活动作业/后台作业

    我通过标准文件输入接收请求参数中的文件 def create file params file upload Upload create file file filename img png end 但是 对于大型上传 我想在后台作业中执行
  • Redis 在键过期时更新排序集

    我有一个 Redis 服务器 其中包含一组键值对和一个排序集 提供这些键值对的键的索引 键值对可以进入 已完成 状态 此时需要在 1 小时后删除它们 这可以通过在键上设置到期时间来简单地实现 但从排序集中清除它们似乎更成问题 我可以有一个过

随机推荐

  • tar包安装

    在Linux操作系统中 常用的软件包一共有两种 rpm包 相当于Windows中的exe软件包 tar gz包 未编译的源码包 软件的编译需要使用gcc编译器 Linux安装 开发工具 gt gcc gcc c tar包解压 基本语法 ta
  • WIN7&WIN10共享打印机0x000000709错误解决方法

    这两天连续碰到709错误 打印机安装正常 共享正常 但通过 ip 打印机名添加共享时就709错误 开始以为是printspooler服务的问题 但试过故障依旧 也检查了共享设置 密码共享是关闭的 guest用户是开启的 为什么呢 最终发现了
  • numpy ndarray 打印格式化

    1 ndarray打印省略问题 np set printoptions threshold np inf 2 ndarray打印换行限制 加上下面这句代码 输出时打印不换行 np set printoptions linewidth 400
  • 用Servlet结合c3p0连接池等写一个简单的注册登录

    首先 给一张截图 上面图是我的整体内容 1 先进入工具类 代码如下 package com qf util import javax sql DataSource import com mchange v2 c3p0 ComboPooled
  • oracle体验实验,Oracle实验三

    1 实验目的 1 掌握表的创建与管理 2 掌握索引的创建与管理 3 掌握视图的创建与管理 4 掌握序列的创建与应用 2 实验环境 Win10 以及Oracle 11g 3 实验要求 1 为图书销售系统创建表 2 在图书销售系统适当表的适当列
  • 机器学习案例6:基于SVM的数字识别

    案例6 基于SVM的数字识别 为什么写本博客 前人种树 后人乘凉 希望自己的学习笔记可以帮助到需要的人 需要的基础 懂不懂原理不重要 本系列的目标是使用python实现机器学习 必须会的东西 python基础 numpy pandas ma
  • 在word中插入显示在同一行的两张图片(且各自带有题注)

    http blog csdn net xiao xia article details 46699271 先将两张图片均导入word中 位置设置为 嵌入文本行中 调整t图片大小使得两图片刚好可以呈现在同一行 如果图片不需要题注 或者两图片共
  • 电动摄像机-多输入多输出(MIMO)非线性自回归系统辨识(NARX)——基于MATLAB

    目录 前言 1 输入输出的数据 测量数据序列 2 非线性ARX IDNLARX 模型 使用Wavenet 小波网络 的初步估计 3 非线性ARX模型 尝试更高阶 非线性ARX模型 调整非线性估计量的单位数 4 非线性ARX模型 尝试其他非线
  • caffe运行时常见错误

    这篇文章记录了我运行python时遇到的错误 以及我的解决方法 可能不够全面 欢迎大家一起讨论 补充 1 import caffe 报错 No module named caffe 原因 没有添加caffe python目录到bash sh
  • 自由手写体字帖pdf_英语字帖5分钟做完专属描红字帖,英文书写体一键生成,还不快来看看?...

    英文书写 一直是初学英语练习的重点 从入门级别的笔顺练习 到后来丝滑的连笔书写 现在还有 衡水体 这种为了提高卷面整体颜值的字体 而制作一份专属练习字帖的难度之大 耗时之长 是家长 教师的难处 有这样一个网站 只需要大家把需要练习的内容输入
  • 实意动词的特征和用法

    文章目录 常见的实意动词 实意动词的否定 实意动词提问 常见的实意动词 come read go watch play fly write 例句 He comes from shanghai she is reading story boo
  • 手机上普通h5页面a标签href方式跳转页面会请求两次解决办法

    必须把a标签的href事件屏蔽掉 解决办法是使用onclick方法 替代href事件 实现页面跳转 具体代码如下 a href span class buy bargain btn 去充值 span a
  • 渗透测试工具ZAP入门教程(4)-设置代理谷歌浏览器

    ZAP 代理原理 如下浏览器 拿Chrome为例 Chrome发出的请求都会先经过 ZAP 然后再由 ZAP 发往服务器 如下图 设置代理 1 Chrome设置只需要在地址栏输入 chrome settings 2 然后在搜索栏输入 代理
  • C语言实现扫雷【超详细讲解】

    目录 一 实现扫雷的基本思路 二 代码实现的具体步骤 三 完整代码 1 saolei h部分 2 saolei c部分 3 test c部分 扫雷和三子棋有很多相似的地方 相信大家认真学习完三子棋再将本篇博客认真学习完 会很好的掌握相关的知
  • 缠论是一种交易方法炒股是不是一定要学习缠论(利用缠论如何选股)

    纠缠论是一种交易方法 有必要学习纠缠论吗 1 复杂的数学思维 思考不仅对投机很重要 对股票交易也很重要 这是一项重要的人类能力 缜密的思考和清晰的表达是做好任何事情的前提 这里的数学思维是指我们高中时做的几何题 假设条件a 条件b 证明结论
  • matlab 聚类

    原网址 http blog sina com cn s blog 62f3c4ef01014wz1 html cited from cited from http hi baidu com coralliu blog item dbde03
  • 学好诊脉 破解难症

    from 老中医 LaoZY cn 学好诊脉 破解难症 中国中医药报 2009年9月24日 高允旺 山西临汾永旺脑病医院 很多乡村或基层医生学中医往往是自学或跟师学习 在学习中 脉诊是非常不好掌握的 但是脉诊确实又非常重要 笔者在临证40年
  • C++11并发——多线程lock_gurad ,unique_lock (三)

    http www cnblogs com haippy p 3346477 html struct defer lock t 该类型的常量对象 defer lock defer lock 是一个常量对象 std lock guard 介绍
  • cannot call getWriter() after getOutputStream()

    cannot call getWriter after getOutputStream 在项目里的一个导出EXCEL方法总是报错 报错内容为 cannot call getWriter after getOutputStream 字面意思很
  • 简单动态字符串

    Sds Simple Dynamic String 简单动态字符串 是 Redis 底层所使用的字符串表示 几乎所有的 Redis 模块中都用了 sds 常规字符串 在 C 语言中 字符串可以用一个 0 结尾的 char 数组来表示 比如说