Redis 数据结构 之 SDS
SDS(simple dynamic string)
,简单动态字符串。s同时它被称为 Hacking String。hack 的地方就在 sds 保存了字符串的长度以及剩余空间。sds 的实现在 sds.c
中。
C语言字符串使用长度为n+1的字符数组来表示长度为n的字符串,并且字符数组的最后一个元素总是空字符'\0',这样的方式存储,时存在安全隐患的,并且它不能满足效率方面的需求。
因此Redis没有使用C原生的string
而是自己构建了SDS
。在Redis里,C语言字符串只用于一些无须对字符串值进行修改的地方,比如:日志。
在Redis中,包含字符串值的键值对都是使用SDS实现的,除此之外,SDS还被用于AOF缓冲区、客户端状态的输入缓冲区。
SDS定义
struct sdshdr{
//字节数组
char buf[];
//buf数组中已使用字节数量
int len;
//buf数组中未使用字节数量
int free;
}
如上图所示,len表示该SDS保存了一个6字节长度(不包含结束符)的字符串,free表示该SDS还有6个字节的未使用空间,buf是一个char类型的数组
,保存了该SDS所存储的字符串值。
高效
相比C语言字符串,使获取字符串长度时间复杂度降为O(1)
而C原生的获取长度为O(N)
遍历整个数组。
安全
同时SDS
杜绝缓冲区溢出,不会像C那样造成数组数据不安全,绝对不会越界。
当需要对SDS进行修改时,API会先检查SDS当前剩余空间是否满足修改之后所需的空间,如果不满足的话API会自动将SDS的空间扩展至足够用的空间然后才进行下一步操作,所以SDS不会出现缓冲区溢出问题。
减少内存分配
C语言字原生符串底层是使用一个n+1个字符长度的char类型数据实现的,所以每次增长或缩短一个原生字符串,程序都要对这个字符串数组进行一次内存重分配操作:
同时因为内存重分配涉及复杂的算法,并且可能需要执行系统调用,所以它通常是一个比较耗时的操作。Redis经常被用于速度要求严苛、数据被频繁修改的场合,如果每次修改字符串都需要执行一次内存重分配的话,那么对于性能会造成很大影响。
SDS 在分配了内存之后(往往空间会存在盈余,也就是空间的预分配),然后自己通过len 和 free 来维护已使用的和未使用的内存,不再依赖系统来重新划分,这样能有效的提升性能。
空间预分配
用于字符串增长操作,当字符串增长时,程序会先检查需不需要对SDS空间进行扩展,如果需要扩展,程序不仅会为SDS分配修改所必要的空间,还会为SDS分配额外的未使用空间,额外分配的未使用空间公式如下:
SDS空间 < 1MB
如果对SDS修改之后,SDS的长度(修改之后len属性的值)小于1MB,那么则分配和len属性同样大小的未使用空间,这时SDS的len属性和free属性的值相同。如:如果修改之后SDS的len将变为10字节,那么程序也会分配10字节的未使用空间,SDS的buf数组实际长度变为10 + 10 + 1 = 21(额外一个字节用于保存结束符\n)
SDS空间 > 1MB
如果对SDS修改之后,SDS的长度大于等于1MB,那么程序会分配1MB的未使用空间。如:修改之后的len将变为10MB,那么程序会分配1MB的未使用空间,SDS的bug数组长度为10MB + 1MB + 1byte
SDS空间 > 512MB
Game over~ 报错!
惰性空间释放
用于优化SDS的字符串收缩操作,当字符串收缩时,程序不会立即执行内存重分配来回收收缩后内存多出来的空间,而是使用free属性记录下来,以备将来使用。
通过空间预分配,Redis可以减少连续执行字符串增长操作所需的内存重分配次数,通过惰性空间释放,SDS避免了缩短字符串时所需的内存重分配操作,并为将来由可能的增长操作提供了优化。
Redis 数据结构 之 SDS的更多相关文章
- Redis数据结构之sds基本操作函数
本文及后续文章,Redis版本均是v3.2.8 本篇文章讲解sds基本操作函数,我们从源码角度来进一步理解. 一.sds创建函数和销毁 sds创建函数 /* Create a new sds stri ...
- Redis—数据结构之sds
Redis是一个Key Value数据库.Redis有5种数据类型:字符串.列表.哈希.集合.有序集合.而字符串的底层实现方法之一就是使用sds.以下描述中请读者注意区分sds是指简单动态字符串这一数 ...
- Redis数据结构:SDS
1. 简单动态字符串(simple dynamic string,SDS)是Redis的默认字符串表示结构,底层的string都是基于SDS实现.Redis基于C语言,并引用了部分C函数. 使用场景: ...
- redis数据结构存储SDS设计细节(redis的设计与实现笔记)
redis虽说是用C语言开发的,但是redis考虑了性能.安全性.效率性.功能等要,redis底层存储字符串实现,自己实现了名为简单动态字符串(Simple dynamic string)简称SDS的 ...
- redis数据结构之SDS
简介 redis源码虽然是C语言实现的,但是Redis没有直接采用C语言传统的字符串表示,而是构建了一种名叫简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS用 ...
- Redis数据结构之robj
本文及后续文章,Redis版本均是v3.2.8 我们知道一个database内的这个映射关系是用一个dict来维护的.dict的key固定用一种数据结构来表达,这这数据结构就是动态字符串sds.而va ...
- Redis 的底层数据结构(SDS和链表)
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件.可能几乎所有的线上项目都会使用到 Redis,无论你是做缓存.或是用作消息中间件,用起来很简单方便 ...
- 深入理解Redis 数据结构—简单动态字符串sds
Redis是用ANSI C语言编写的,它是一个高性能的key-value数据库,它可以作用在数据库.缓存和消息中间件.其中 Redis 键值对中的键都是 string 类型,而键值对中的值也是有 st ...
- Redis数据结构底层知识总结
Redis数据结构底层总结 本篇文章是基于作者黄建宏写的书Redis设计与实现而做的笔记 数据结构与对象 Redis中数据结构的底层实现包括以下对象: 对象 解释 简单动态字符串 字符串的底层实现 链 ...
随机推荐
- PHP文件目录操作
目录操作 is_dir ( $path ) 判断当前路径是否为目录 ,返回布尔 opendir ( $path ) 打开路径目录,返回资源 readdir ( $handle ) 读取当前打开目录下一 ...
- Flink kuduSink开发
1.继承RichSinkFunction (1)首先在构造方式传入kudu的masterAddress地址.默认表名.TableSerializationSchema.KuduTableRowConv ...
- Docker 入门:镜像
主要内容: 什么是镜像 下载镜像 pull 设置下载加速源 查看镜像 上传镜像 push 什么是镜像(image) 镜像是一个文件系统,提供了容器运行时需要用到的文件和参数配置.相当于平时在使用某个软 ...
- vue路由中使用keep-alive 以及activated和deactivated 钩子
本次只是记录下开发中碰到的问题. 最近做一个活动页面,涉及到角色和权限的问题,需要跳转很多页面,于是vue-router走起,顺便keep-alive也用起来了,嗯,跳转的很爽,但是一个详情页面组件, ...
- 插入与读取Blob类型数据
BlobTest package com.aff.PreparedStatement; import java.io.File; import java.io.FileInputStream; imp ...
- 树莓派 ubuntu mate 16.04 系统默认软件源
deb http://ports.ubuntu.com/ xenial main restricted universe multiverse deb-src http://ports.ubuntu. ...
- 副业收入是我做程序媛的3倍,工作外的B面人生
到“程序员”,多数人脑海里首先想到的大约是:为人木讷.薪水超高.工作枯燥…… 然而,当离开工作岗位,撕去层层标签,脱下“程序员”这身外套,有的人生动又有趣,马上展现出了完全不同的A/B面人生! 不论是 ...
- Linux磁盘与文件系统管理概要
Linux磁盘与文件系统管理 硬盘组成与分区 硬盘组成 圆形的盘片(主要记录数据) 机械手臂与磁头(可读取盘片上的数据) 主轴马达,转动盘片,让机械手臂的磁头在盘片上读取数据 扇区(Sector)为最 ...
- Java实现 LeetCode 650 只有两个键的键盘(递归 || 数学)
650. 只有两个键的键盘 最初在一个记事本上只有一个字符 'A'.你每次可以对这个记事本进行两种操作: Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的). ...
- Java GUI 窗体事件
import java.awt.Frame; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; publi ...