看完这个还不了解redis的SDS,半夜你来扒我家墙头
Posted king哥Java架构
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了看完这个还不了解redis的SDS,半夜你来扒我家墙头相关的知识,希望对你有一定的参考价值。
概述:
我们都知道redis底层是用C语言实现的,而C的字符串是以‘\\0’来判断结束的,是一个对特殊字符存储不安全的。那redis是怎么做到存储二进制安全的呢?
重头戏-redis中的字符串
redis中还是有用到C中字符串的地方,比如一些不需要修改的字面量一些reids要输出的日志信息等。而需要修改的字符串redis抽象成了我们的SDS对象:简单动态字符串(simple dynamic string,SDS)。这部分的源码对应在这两个文件中
sds.h
和 sds.c
SDS的定义
每个 sds.h/sdshdr
结构表示一个 SDS 值,结构如下:
struct sdshdr {
// 记录 buf 数组中已使用字节的数量
// 等于 SDS 所保存字符串的长度
int len;
// 记录 buf 数组中未使用字节的数量
int free;
// 字节数组,用于保存字符串,
char buf[];
};
我们的buf中存放的就是我们真正的按照\\0结束的字符串内容(在3.2版本之后此处改成了一个指针会根据不同长度指向不同的结构),len是我们的字符串内容的长度。还可以看到有一个free的子段,这个子段的作用先卖个关子下边说
如果你觉得自己学习效率低,缺乏正确的指导,可以加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧!
[Java架构群]
群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的JAVA交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
SDS中free的作用
在c语言中使用不当经常会有内存溢出的问题,导致我们的字符串被覆盖,而redis是怎么避免这种问题的出现的呢?
首先我们在redis中插入一个key:
> set demo hello;
这个时候的SDS对象是:
struct sdshdr {
int len; = 5
int free; = 0
char buf[]; = 'hello'
};
> set demo ‘hello world’;
这个时候的SDS对象是:
struct sdshdr {
int len; = 11
int free; = 11
char buf[]; = 'hello world'
};
> set demo 'hello world wang';
struct sdshdr {
int len; = 16
int free; = 6
char buf[]; = 'hello world wang'
};
我们在set hello world之后 redis会根据我们的free子段去判断需不需要向操作系统申请内存,如果free够用则不申请。这个时候就涉及到redis的内存分配策略了,为了避免多次向操作系统申请内存的开销,redis在每次申请都会按照当前len的两倍去申请(当len于1M时候就只会多申请1M),也就可以解释我们的free为什么是11了,这就是redis的空间预分配。
我们可以看下redis-5源码涉及到内存分配的策略,扩容是这个方法XDM可以去看看 sds sdsMakeRoomFor(sds s, size_t addlen)
还有一个惰性空间释放的概念会涉及到我们的free子段,当我们将redis的字符串内容减少的时候,redis并不会立马释放内存而是仅仅修改free子段,以便下次使用。
总结
- 因为SDS有存储字符串长度len,所以我们获取redis字符串长度是一个O(1)的操作。
- len的存在避免了内存溢出的问题
- 通过内存分配策略,减少了字符串修改时候的内存分配次数
最后
给大家分享一篇一线开发大牛整理的java高并发核心编程神仙文档,里面主要包含的知识点有:多线程、线程池、内置锁、JMM、CAS、JUC、高并发设计模式、Java异步回调、CompletableFuture类等。
码字不易,如果觉得本篇文章对你有用的话,请给我一键三连!关注作者,后续会有更多的干货分享,请持续关注!
以上是关于看完这个还不了解redis的SDS,半夜你来扒我家墙头的主要内容,如果未能解决你的问题,请参考以下文章