redis是使用c语言编码的,string的实现是使用了一种称为sds动态字符串的结构体,如下所示
struct sdshdr {
int len;
int free;
char buf[];
}
len就是当前redis中key对应value的长度(已使用字节数),free指存储字符串数组buf的剩余空间(未使用字节数),即buf的长度为len+free+1,在C语言中字符串是由空字符为结尾的,这个1正是指结尾的空字符。结构如下图所示:
因为redis中value值会经常发生变化,长度可能也会经常改变,那么为了避免为字符串频繁的申请或释放空间(学过C语言的应该都知道,C中空间需要手动申请释放,而java可以自动回收),减少内存重分配次数,redis中使用了空间预分配、惰性空间释放这两种方式来优化。
1.空间预分配:当字符串长度增加,buf长度已经不满足要求的时候,如果字符串长度在1M以下,那么每次会预分配一倍的长度,假如当前buf长度为10,字符串长度为13,那么会分配26+1字节长度,的buf数组,若字符串长度在1M以上,那么每次会预分配1M的空间,此时buf实际长度为 字符串长度+1M+1byte(空字符)。通过这种方式减少频繁为字符串分配空间的次数。同时会修改len和free的长度。
2.惰性空间回收:当字符串长度变小时,并不真正的将空间回收,而是修改free和len的长度。通过惰性空间释放策略, SDS 避免了缩短字符串时所需的内存重分配操作, 并为将来可能有的增长操作提供了优化。
redis中数据结构具体应用
1.redis中string经常用作k-v缓存
2.set,我们经常在项目中使用set来获取不重复的一个集合,如果想在分布式环境中也获取一个不重复集合就可以使用redis中的set结构,并且可以基于set做并集、交集、差集等
3.sort set,与set类似,不过它除了能够存储member之外还可以存储一个score分数,集合中的member按照分数从小到大排列,如果分数一样就按照member的字典序升序排列,可以用它来做排行榜(member为用户id,score为充值金额或热度),消息的延迟发送(member为消息体,score为待发送时间,扫描整个sort set如果score小于现在的时间则发送,然后从集合中删除member对应内容)
4.list :在redis中它是一个双向链表,我们可以用它来存储一些list结构的数据,比如像粉丝列表、文章评论列表等等,还可以基于lrange命令,读取某个闭区间的元素,实现list的分页
5.hash,可以看成是一个map类型的数据结构,我们可以用它来做一些简单对象的缓存,map中存储对象的属性name和对应的value,例如存储购物车信息,redis key为用户的id信息,map中存储商品信息和购买数量