Redis 数据结构之简单动态字符串SDS
几个概念
1:key对象 数据库存储键值对的键,总是一个字符串对象。
2:value对象 数据库存储键值对的值,可以是字符串对象,list对象,hash对象,set对象,sorted set对象。
例如:
set msg "hello world" 则redis在数据库中创建一个新的键值对,键和值都是一个字符串对象,底层实现都是一个sds对象。
rpush fruits "apple" "banana" "cherry" 则redis在数据库中创建一个新的键值对,键是一个字符串对象,底层实现是一个sds对象;值是一个列表对象,列表对象包含了三个字符串对象,由三个sds对象实现。
3:sds (sample dynamic string)
定义:
struct sdshdr{
//记录buf数组中已使用字节的数量
//等于sds所保存字符串的长度
int len;
//记录buf数组中未使用的字节数量
int free;
//字节数组用来保存字符串
char buf[];
}
4:C语言的简单字符串的表示方式不能满足redis对字符串在安全性、效率以及功能上的要求,故引用sds字符串
4.1 sds字符串获取字符串长度效率更高,时间复杂度为o(1),c字符串的为o(n),保证获取长度的工作不会成为redis的性能瓶颈。(更新sds长度工作是由sds的api在执行时自动完成的);
4.2 杜绝缓冲区溢出 s1如果没有分配足够的内存空间,扩展时s1的数据就会溢出到下一个相邻的s2空间中,而sds的空间分配时,api会先检查sds的空间是否满足修改所需的要求,如果不满足,api会自动将sds空间扩展到执行修改所需的大小,然后在执行修改操作;
4.3 减少修改字符串时带来的内存重新分配次数
1) c字符串执行加长操作,如果忘记重新分配内存就会出现缓冲区溢出,如果执行缩短操作,如果忘了重新分配内存就会出现内存泄露,由于redis是数据库,对速度要求苛刻,如果数据频繁修改,使用c字符串就需要频繁执行内存分配,执行内存分配就会占据修改字符串的大部分时间,如果频繁发生,还会对性能造成影响,故redis使用sds字符串作为底层的实现。
2) sds字符串 buf数组长度不一定等于字符数量加一,数组包含未使用字节,这个长度存储在free属性上
3) 空间预分配:优化sds字符串增长操作,api对sds进行空间扩展的时候,程序不仅会为sds修改所需的空间,还会为sds分配额外的未使用空间 公式:扩展后小于1m,分配和len属性相同的未使用空间,大于等于1m分配1m的未使用空间。这样在执行扩展操作时,api会先检查未使用空间是否足够,如果足够就直接使用未使用空间,减少内存分配次数,基于这种策略,在执行n次修改操作时,重新分配内存次数从n次降为最多n次。
4) 惰性空间释放:优化字符串缩短操作,在进行缩短操作时,程序不会立即重新分配内存回收缩短后多余出来的字节,而是使用free属性记录起来,等待将来使用,如果有增长操作可以直接使用。当然sds也提供了释放sds未使用空间的api,所以不必担心惰性释放带来的内存浪费问题。
4.4 二进制安全 c字符串中必须符合某种编码,出来字符串末尾,不能包含空字符,所以c字符串只能保存文本数据,不能存储图片、音频、视频等二进制数据,sds的api会以二进制的方式处理buf数组里的数据。使得redis可以保存任意格式的二进制。
4.5 兼容部分c函数 sds遵循空字符结尾的惯例,api会将sds保存数据的末尾设置为空字符,并且会在buf分配空间时多分配一个字节,这样可以让保存文本数据的sds重用string.h库定义的一些函数。
小结:
c字符串获取长度复杂度o(n),sds为o(1)
api不安全可能造成缓冲区溢出,api安全不会造成缓冲区溢出
修改字符串长度n次会执行n次内存分配,最多n次
只能保存文本数据,可以保存文本或二进制数据
可使用所有string.h库函数,只能使用部分函数
Redis 数据结构之简单动态字符串SDS的更多相关文章
- Redis数据结构之简单动态字符串SDS
Redis的底层数据结构非常多,其中包括SDS.ZipList.SkipList.LinkedList.HashTable.Intset等.如果你对Redis的理解还只停留在get.set的水平的话, ...
- redis 系列3 数据结构之简单动态字符串 SDS
一. SDS概述 Redis 没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string, SDS)的抽象类型,并将SDS用作Redis的默 ...
- Redis数据结构之简单动态字符串
Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组), 而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型, 并将SDS用作Redi ...
- Redis核心原理-简单动态字符串SDS
SDS简介 Redis是C语言编写的,但没有使用c语言的字符串结构,而是自己实现了一套简单动态字符串 simple dynamic string 简称SDS,SDS兼容C语言的字符串类型,原理类似Ja ...
- 图解Redis之数据结构篇——简单动态字符串SDS
图解Redis之数据结构篇--简单动态字符串SDS 前言 相信用过Redis的人都知道,Redis提供了一个逻辑上的对象系统构建了一个键值对数据库以供客户端用户使用.这个对象系统包括字符串对象 ...
- Redis底层探秘(一):简单动态字符串(SDS)
redis是我们使用非常多的一种缓存技术,他的性能极高,读的速度是110000次/s,写的速度是81000次/s.这么高的性能背后,到底是怎么样的实现在支撑,这个系列的文章,我们一起去看看. redi ...
- 深入理解Redis 数据结构—简单动态字符串sds
Redis是用ANSI C语言编写的,它是一个高性能的key-value数据库,它可以作用在数据库.缓存和消息中间件.其中 Redis 键值对中的键都是 string 类型,而键值对中的值也是有 st ...
- 【redis】redis底层数据结构原理--简单动态字符串 链表 字典 跳跃表 整数集合 压缩列表等
redis有五种数据类型string.list.hash.set.zset(字符串.哈希.列表.集合.有序集合)并且自实现了简单动态字符串.双端链表.字典.压缩列表.整数集合.跳跃表等数据结构.red ...
- 【Redis】简单动态字符串SDS
C语言字符串 char *str = "redis"; // 可以不显式的添加\0,由编译器添加 char *str = "redis\0"; // 也可以添加 ...
随机推荐
- 《深入理解Android2》读书笔记(三)
接上篇<深入理解Android2>读书笔记(二) PackageManagerService PackageManagerService负责系统中Package的管理,应用程序的安装.卸载 ...
- CodeForces 144B Meeting
暴力. 题目只要求计算边上的点就可以了,一开始没看清题意,把内部的也算进去了.内部的计算可以延迟标记一下,但这题没有必要. #include<map> #include<set> ...
- Bzoj1486/洛谷P3199 最小圈(0/1分数规划+spfa)/(动态规划+结论)
题面 Bzoj 洛谷 题解(0/1分数规划+spfa) 考虑\(0/1\)分数规划,设当前枚举到的答案为\(ans\) 则我们要使(其中\(\forall b_i=1\)) \[ \frac{\sum ...
- Python安装scrapy提示 error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools&quo ...
- BestCoder Round #65 (ZYB's Premutation)
ZYB's Premutation Accepts: 220 Submissions: 983 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: ...
- EasyUI学习总结(五)——EasyUI组件使用(转载)
本文转载自:http://www.cnblogs.com/xdp-gacl/p/4084520.html 一.EasyUI组件的简单介绍 easyUI提供了很多组件让我们使用,如下图所示:
- ListView EditText 实现的三种方式
原文网址:http://blog.sina.com.cn/s/blog_682139d001013omd.html 这段时间搞一个android表格,真是搞死人,让我想到iphone开发是何其的简单啊 ...
- kosaraju算法求强连通分量
什么是强连通分量?在这之前先定义一个强连通性(strong connectivity)的概念:有向图中,如果一个顶点s到t有一条路径,t到s也有一条路径,即s与t互相可达,那么我们说s与t是强连通的. ...
- 连接mysql时1045错误的解决办法
重装系统后,今天mysql提示1045错误无法连接上,找了很久得出方法如下: 修改root密码即可正常. 1,进入mysql控制台选择: 2,use mysql; 3,update user set ...
- 用GDB 调试Java程序
陈皓 http://blog.csdn.net/haoel 背景 想要使用GDB调试程序,就需要用GNU的编译器编译程序.如:用GCC编译的C/C++的程序,才能用GDB调试.对于Java程序也是 ...