你要是问我,在程序世界中我们程序员打交道最多的一种数据类型是什么?
我肯定会回答你是 字符串
那么在Redis中是如何实现的这种字符串数据结构呢?在Java中我们有 java.lang.String
类,在C语言中通过char[]
字符数组实现的字符串,总所周知Redis是由C语言实现的,那么Redis中的字符串就是通过C语言的char[]
字符数组实现的吗?
不是的,Redis是通过一个名叫SDS(Simple Dynamic String)简单动态字符串实现的
接下来,我们就来研究研究,为什么不直接使用C字符串,而是要在实现一套Redis自己的字符串数据结构。请系好安全带,马上发车!
struct sdshdr{
//记录buf数组中已使用的字节的数量
//等于SDS保存的字符串长度
int len;
//buf数组中未使用的字符个数
int free;
//字符数组,用于保存字符串
char buf[];
}
上面这个名为sdshdr
的结构体就是Redis中SDS的定义,很简单的对吧
下面使用两幅插图,形象的展示一下SDS中存放数据的时候是个什么样子的
图1
在图1中我们可以看到,当存放一个叫做‘Redis’这样的一个字符串的时候,在SDS中的一个内存分布的情况
SDS遵守C字符串的规定,在字符串的末尾保存一个字节的‘\0’表示字符串结束,遵守这规定的好处是,SDS可以直接使用C字符串函数库中的一部分函数
图2
在图2中我肯可以看到和图1的最大的区别就是多出了3个分配未被使用的字节空间,这种空间预分配的策略正是SDS和C字符串实现上的最大的不同之处。
传统的C字符串使用长度N+1的字符数组表示一个长度为N的字符串,并且字符串以’\0’结尾。
C语言使用这种简单的字符串表示方式,并不能满足Redis在对字符串的安全性,效率以及功能方面的要求,所以SDS需要去解决C字符串不能满足的这些问题。
在SDS中因为存储了len
表示字符串长度的属性,所以可以以O(1)的时间复杂度获取字符串的长度;在C字符串中,需要遍历char[]
字符数组才能获取到字符串的长度,时间复杂度为O(N);
在C字符串中,如果用户在执行strcat
函数的时候,会存在内存覆盖的问题。比如有两个字符串,它们在内存中刚好是连续分布存在的。如下图所示:
图3
有S1 ‘Bob’,S2 ‘Dave’,当执行 strcat(s1,“niu”)的时候,那么就会出现如下情况
图4
字符串S2原本的值被覆盖了,这种现象又被称为缓冲区溢出。SDS为了避免这种情况,在修改的时候,会先检查SDS的空间是否满足修改的所需要求,如果不满足的话,会自动将SDS的空间扩展至执行修改所需的大小,然后才执行实际的修改操作。这样就避免了缓冲区溢出的问题。
由于C字符串中不会保存自身的长度,所以它的长度总是和被使用的字节数相等,就会导致了每次修改字符串的时候,都会重新分配一块连续的内存空间,然后在修改。内存分配是一件耗时的操作,如果一个字符串被修改的频率不高,那么使用这种方式也是Ok的,但是Redis作为一款数据库它是需要解决这种对数据频繁修改的问题的。
在SDS中通过实现了空间预分配和惰性空间释放这两种优化策略
空间预分配用于优化SDS增长的操作:当对一个SDS进行修改的时候,在需要对SDS进行空间扩展的时候,不仅为SDS分配修改所必要的空间,还会对SDS分配未使用的空间。
其中未被使用的空间分配数量算法如下:
惰性空间释放用于优化SDS的字符串缩短的操作。当一个SDS需要缩短的时候,并不会立即使用内存重分配来回收缩短后的字节,而是使用free属性将这些字节数量记录下来,并等待将来使用
在C字符串中,因要求在字符串中除了在末尾,其它位置上不能包含空字符,否则就会被误识别为字符串结尾。这个限制了C字符串只能保存文本数据,不能存储二进制的数据,例如视频、音频等。
SDS不会有任何限制,当数据被存放进去的时候是什么样子,在取出来的时候就是什么样子的。
总结一下C字符串和SDS字符串的主要区别
C字符串 | SDS字符串 |
---|---|
获取字符串长度时间复杂度O(N) | 获取字符串长度时间复杂度O(1) |
API不安全,会造成缓冲区溢出 | API安全,不会造成缓冲区溢出 |
修改字符串长度N次,必然进行N次内存重新分配 | 修改字符串长度N次,最多进行N次内存重新分配 |
只能保存文本数据 | 能保存文本、视频等二进制数据 |
能使用<string.h>所有的函数 | 能使用<string.h>部分的函数 |
1.启动hiveserver2服务器,监听端口10000$>hive --service hiveserver2 &netstat -anop | grep 10000 2.通过beeline命令行连接到hiveserver2$>beeline //进入beeline命令行(于hive --service beeline)$beeline>!help //查看帮助$
json对象:比如现在有一个json对象为jsonObj,需要给这个对象添加新的属性newParam,同时给newParam赋值为pre。做法如下:var jsonObj={ 'param1':22, 'param2' :33};现在给jsonObj添加一个新的属性newParamjsonObj.newPara...
1,上传win7镜像文件到/p_w_picpaths/iso/文件夹下2,开始安装[[email protected]]#virt-install--name=win7--ram512--vcpus=2--diskpath=/p_w_picpaths/test/win7.img,size=8--accelerate--cdrom/p_w_picpaths/iso...
很多朋友对于IBM海量的描述信息感觉到束手无策,以下信息均可以在 中使用快查功能查询到,另外可以查看到具体的配件对应的PN号,查询可以适用于哪些整机,这是单纯本文档无法实现的功能。更多详情请移步。 7856 Power Cables, 4x, 13U 电源线,4x, 13U7857 Power Cables, 4x, 19U 电源线,4x, 19U7858 Power Cab
当我跑步时git pull origin test,我得到fatal: unable to connect to cache daemon: Permission denied然后提示输入github用户名和密码。该目录位于我的主文件夹(~/www/software)下。有任何想法吗?如果使用sudo,它可以工作,但是我不认为必须在自己的主文件夹中使用su!这是结果ls -l:drwxrwxrwx...
ACDSee是一款由ACD Systems开发的看图工具,ACDSee支持快速开启、浏览多数的影像格式。ACDSee不单单只能浏览图片还可以针对图像进行简单的编辑,小伙伴们还可以使用ACDSee针对JPG、BMP、GIF等图像格式进行任意转换。小伙伴们如果有用到BMP格式文件也可以借用ACDSee转换成JPG格式,从而缩小课件的体积哦。ACDSee下载地址ACDSee普通下载地址ACDSee通用网络下载 ACDSee电信网络下载ACDSee其他版本ACDsee 10.0免费版 AC
使用 Kattle 连接 SqlServer 是的配置
/*实验说明: 此程序兼容了有源和无源蜂鸣器实验接线: 独立按键模块-->单片机管脚 K1-->P31 K2-->P30 蜂鸣器模块-->单片机管脚 BEEP-->P15实验现象: 按下K1键,蜂鸣器发出声音,按下K2键,蜂鸣器停止发声*/#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器typede...
重启网卡的几种方法:一、network利用root帐户# service network restart二、ifdown/ifup# ifdown eth0# ifup e...
在Emacs中使用gdb调试程序 http://emacser.com/emacs-gdb.htm 1 引言 2 准备工作:将调试信息编译在程序中 3 开始:开启Emacs的调试模式GUD 3.1 运行...
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012313335/article/details/73733651 Matlab 2016a 安装包及破解教程百度云分享链接:链接:https://pan.baidu.com/s/1i6B...
目录目的:一、例子:二、分析:2.1、$2.2、-C目的:分析这三个的用法一、例子:KERN_DIR = /work/system/linux-2.6.22.6all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.orde...