redis面试(一)String底层剖析
创始人
2024-11-14 20:35:05
0

前言

今天开始更新一些redis相关的知识点,初步计划是redis的数据类型,以及redis分布式锁
本章节主要是redis的String类型

字符串SDS

一般情况下我们认为的redis 字符串就是String,但是我这边要说的是底层String类型。

redis底层是C语言,但是C语言中的String有一定的缺陷,所以redis开发了一个自己的字符串类型 SDS 也就是simple dynaic string,专门的数据结构,保证字符串的完整性 动态字符串

c语言中的字符串是 r,e,d,i,s,\0 这种n+1的形式存储的,读取的时候一个个的读取,一直到 \0 这个数据
获取字符串长度的时候,还要遍历一遍

redis sds的字符串类型如下

struct sdshdr { 	int len;	// 已使用字节数= 字符串长度 	int free; 	// 未使用字节数 	char buf[];	// 字符串本身内容 } 

比如:
sdshdr
free=0
len=5
buf-> [r,e,d,i,s,\0]

c字符串里规定除了末尾可以有一个\0空字符以外,内容里不能包含空字符,否则读到空字符就认定这个字符串结束了,所以导致c字符串只能保存文本,不能保存图片和音视频一类的二进制数据

二进制问题

re\0di\0s
re di s
如果你要是在内容里包含了很多空字符的话,你就不是二进制安全的了
但是sds实现了二进制安全,而且允许内容里包含\0,这是为什么呢,因为sds里有一个len,他是根据len来读取指定字节数量的字符的,而不是根据\0来判断字符串是否结束了,这是一个很关键的优化,通过这个就可以实现二进制安全了
但是redis还是遵守了末位是\0的c规范,这样保存的字符串,就可以复用c语言的一些函数了,因为c语言函数是这么规定的

c语言原生字符串,strlen,获取字符串长度,遍历,O(n),二进制不安全的,对于二进制数据来说,图片、视频、音频、压缩文件,这种数据都是以一大堆的二进制串来存储的,里面肯定会有很多\0空字符,对于c语言来说,读取的时候,一定要按照\0来截断,肯定不行的

二进制不安全,原生的c语言字符串没法安全的存储二进制数据

redis里面的sds,他里面有两个关键的字段,len和free,buf = [] 跟c语言没太大差别,len和free很厉害,free的作用,我们还没讲,len有2个作用,直接读取len,strlen,O(1),读取buf里的数据,不是遍历看到\0就停止

根据len读取指定字节数量的buf数字的内容,形成一个完整的内容,对于我们来说,redis里的sds存储二进制的数据,图片、音视频,就算buf里包含了很多\0空字符,根据len来读取,不是根据\0来截断,redis sds可以实现二进制安全性,安全的保存二进制数据

避免缓冲区溢出

redis和spark两个字符串,在内存地址里,连续的存储在了一起
[r,e,d,i,s,\0,s,p,a,r,k,\0]

str = redis

strcat(str, sentinel) -> 插入忘记了给sentinel字符串分配内存空间

c语言原生字符串可能搞出缓冲区溢出的问题,那就是说,r,e,d,i,s,s,p,a,r,k,连续两个字符串,redis和spark,结果我们要是用c语言的strcat函数,搞了一个strcat(str, ‘sentinel’),想要把sentinel拼接到redis字符串后面去,又忘了给sentinel提前分配内存空间,就会导致,r,e,d,i,s,s,e,n,t,i,n,e,l,直接覆盖掉spark了,这就是缓冲区溢出
[r,e,d,i,s,\0,s,e,n,t,i,n,e,l,\0]

sds(free=0,len=5,buf[r,e,d,i,s,\0]) -> sds(free=13,len=13,buf[r,e,d,i,s,s,e,n,t,i,n,e,l,\0])

sds会自动检查字符串扩容空间是否足够,不够就扩容空间,扩容完毕了再修改字符串的内容,比如sdscat就是这样的拼接字符串的函数,比如一开始sds的free=0,len=5,buf=redis,但是现在你要扩容加上sentinel了,此时就会先扩容,free=13,len=13,buf=redissentinel

内存预分配

除了扩容,他还会额外的给13个自己的free空间

c字符串在拼接或者截断的时候,要不然就得扩容数组,要不然就是释放空间内存,就是有频繁的内存重分配动作,这个内存重分配是很耗费时间的,涉及到os系统调用,redis频繁修改字符串,频繁内存重分配,那就真的是很尴尬

sds为了避免这种频繁内存重分配的问题,才设计了free,这个free可以实现内存预分配和惰性释放,每次sds的内存空间要进行扩容的时候,扩容完毕后,都会根据一个公式,提前计算出free,预分配一定的内存空间出来

扩容后,sds长度小于1mb,就把free设置为跟len一样,做一个双倍预分配,如果扩容后len大于1mb了,就把free设置为1mb就可以了,毕竟不能无限制的扩容下去,这个预分配后,就是底层c里的数组,留了一定字节数量的空间,但是没有真正使用

这样你后续再修改字符串,直接就用free空间就可以了,避免了频繁重分配内存了

惰性释放

如果缩短一个字符串,那么就会把字符串正常缩短,然后len设置为字符串长度,free就是原长度-现长度,以后如果要增长,还可以用free,如果确实要释放内存空间,sds提供了api来释放,但是他是不会立即释放掉的。而是在过一段时间之后,发现空间不足了,才会释放掉这部分空间

相关内容

热门资讯

总结辅助!购买的wpk辅助在哪... 总结辅助!购买的wpk辅助在哪里下载,德普之星辅助软件,解密教程(存在有挂)购买的wpk辅助在哪里下...
教程攻略!聚财平台辅助,小闲川... 教程攻略!聚财平台辅助,小闲川南宜宾辅助,办法教程(有挂工具)1、全新机制【小闲川南宜宾辅助ai辅助...
玩家亲测!poker worl... 玩家亲测!poker world辅助器,雀友会广东潮汕麻雀,攻略教程(有挂教学)1、全新机制【雀友会...
法门辅助!wpk控制牌是真的吗... 法门辅助!wpk控制牌是真的吗,hhpoker怎么破解,解迷教程(有挂讲解)1、起透看视 wpk控制...
查到实测辅助!情怀莆仙外挂,湖... 查到实测辅助!情怀莆仙外挂,湖北逍遥卡五星辅助,绝活儿教程(果真有挂)1、全新机制【湖北逍遥卡五星辅...
据统计!wepoker怎么设置... 据统计!wepoker怎么设置房间,hhpoker大菠萝有没有作比,模板教程(有挂技巧)1、全新机制...
模板辅助!wepoker透视a... 模板辅助!wepoker透视app下载,wepoker俱乐部辅助,曝光教程(发现有挂)1、下载好we...
教程辅助!乐乐围棋入门辅助,爱... 教程辅助!乐乐围棋入门辅助,爱来大菠萝挂,教材教程(有挂分析)1、不需要AI权限,帮助你快速的进行乐...
技术分享!werplan免费挂... 技术分享!werplan免费挂下载,天酷游戏交易平台,手筋教程(有挂方法)1、下载好天酷游戏交易平台...
法门辅助!wepoker开脚本... 法门辅助!wepoker开脚本视频,aapoker透视脚本下载,了解教程(有挂教学)aapoker透...