前文中提到,Redis的字符串对象的底层数据结构有三种,分别是整数编码、EMBSTR编码和SDS编码。在不同使用场景下进行相互切换,起到节约内存的作用。
1.整数编码
针对将某个key对应的值设置为整数类型的情况,有以下两种情况
举个例子,我们使用如下命令:
set a 11111
将键a的值设置为11111(设置为11111是因为共享对象的范围是[0,10000]),我们通过GDB设置断点,打印相关变量:
从图中可以看到,字符串对象的encoding字段从RAW变成了INT,对应的底层数据结构指针也发生了相应的变化。使用【object encoding】命令查看编码类型。
2.EMBSTR编码
EMBSTR编码是专门用于存储短字符串而实现的,当字符串的长度不大于39个字节的时候,就会将该字符串对象编码为EMBSTR类型。EMBSTR编码使用一块连续的内存空间,可以更好的利用到cache line。此外,对比RAW编码,在内存分配和内存释放的次数上都降低了一倍。
其中,创建EMBSTR编码的字符串代码如下:
代码中可以看到,实际上EMBSTR的底层数据结构也是复用了sdshdr结构体,但是在创建的时候只调用了一次zmalloc,而RAW编码则会调用两次,因此,EMBSTR是将redisObject和sdshdr存放到一块连续的内存空间中去了。值得一提的是,Redis并没有为EMBSTR实现修改的方法,所以任何对EMBSTR编码的字符串的修改(例如append),都会使其从EMBSTR转为RAW编码,再进行修改操作。
Redis在处理客户端请求命令时,会针对命令字符串的长度选择使用EMBSTR还是RAW,在后面说到“服务器与客户端交互”时还会具体介绍,代码如下(networking.c:processMultibulkBuffer):
3.SDS编码
SDS编码类型的字符串是Redis基于自身实现的简单动态字符串,它的结构如下图所示:
从图中可以看出,SDS通过len字段记录字符串实际长度,通过free字段记录字符串剩余长度,此外由于Redis是C语言编写,所以继承了C语言字符串以“\0”作为终止符的规则,额外分配一个字节空间给\0(为了兼容C字符串API),因此图中这个字符串(hello)总共占用的内存空间为5+5+1=11个字节。那么,为什么Redis要设计SDS而不直接使用C语言的字符串呢?主要有以下几点:
4.思维导图
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。