以下涉及到的源码均来自 https://github.com/redis/redis (branch 6.2)
背景知识
在6.2这个版本redis支持的数据结构如下
![0b41633e9c8ce01e29d48e2fdcb3ac58.png](https://i-blog.csdnimg.cn/blog_migrate/2eeae92e2c4b7cab44c0e7c092bc80d9.jpeg)
可能大家比较熟悉和用得比较多的是前5种数据结构(后面两种是后来加入的)
redis数据结构编码类型
![90a521652d2830aa7d3f87dfa14cf9c5.png](https://i-blog.csdnimg.cn/blog_migrate/c1239a917517c425c009720a70e29db1.jpeg)
其中字符串涉及到的编码类型有
OBJ_ENCODING_RAW(原生)
OBJ_ENCODING_INT(整型)
OBJ_ENCODING_EMBSTR(紧凑型, 前提条件字符串长度小于等于44,后面再分析这个数字是如何来的)
这些数据结构在redis内部表示
![0b6e8158850e9e59c4d4474fac745dc9.png](https://i-blog.csdnimg.cn/blog_migrate/6a4c6cd7026230e8ff58cd3f22ba6c31.jpeg)
从redisObject可以算出该结构体占用内存大小
4bit + 4bit + 24bit + 4Byte + 4Byte = 12Byte
即是 sizeof(struct redisObject) = 12 (后面有用到)
Redis字符串(string)内部数据结构Sds
![89425f212d94d822ddb98f37f7287a44.png](https://i-blog.csdnimg.cn/blog_migrate/9e68c7d64ee696ec09658c0db566bb28.jpeg)
从上面看起来sds和普通字符串没啥区别, 其实redis为了节省内存做了更细的划分
![2dcd411264409dbd3c3e4a6d0f704f31.png](https://i-blog.csdnimg.cn/blog_migrate/c9838294008d5290876ff68069116a18.jpeg)
![8575c2c3959be7ed47d50d0f050fd904.png](https://i-blog.csdnimg.cn/blog_migrate/0a70b46c6eaf504d112c8e1934b84d36.jpeg)
除了sdshdr5的结构不太一样,其它结构都一样(适用于不同长度的字符串)
len -> 已使用的长度
alloc -> 分配的长度(除去了sds头和空'0'结束符 - 可以更方便的计算可用长度 avail = alloc - len)
flags -> 低三位表示sds类型, 高五位目前还未使用到
buf[] -> 实际字符串数据
sds header里存有len长度的一个解释:
You can print the string with printf() as there is an implicit 0 at the end of the string. However the string is binary safe and can contain 0 characters in the middle, as the length is stored in the sds header.
来看看sds的创建过程就能大概明白了
sds创建
![5cd6f1c541aa1db0f5cb81082cd8d3ef.png](https://i-blog.csdnimg.cn/blog_migrate/28a9e2056d831c231d5878c9eeda2173.jpeg)
![1975591ad3d9f36bfbb6afce13ff8d0d.png](https://i-blog.csdnimg.cn/blog_migrate/35d3a2b76757b66702c5bdd7ac902129.jpeg)
1. 如何确定新建的sds类型
![dc37be265cebb3071fb47d8fb327ad13.png](https://i-blog.csdnimg.cn/blog_migrate/9ec2bb4ad17776dedad6e7515adb37d7.jpeg)
2. 计算sds header大小
![6a7d8bc97919725d100933eabbe96583.png](https://i-blog.csdnimg.cn/blog_migrate/1c634ef70c4813acc2d6a66074000836.jpeg)
3. 分配内存
![58e4ac90b22786129116c7ae257ed897.png](https://i-blog.csdnimg.cn/blog_migrate/719c868e50940a15cb4d781d0de1c6a7.jpeg)
4. 内存初始化
![6c83f4e0a943cc02883e1d937efafe95.png](https://i-blog.csdnimg.cn/blog_migrate/1dcba1bd4aec4c39784d2b6ccc59553e.jpeg)
5. sds结构设置
![d09bdc777ef7c1eb5390999a4af1a3e3.png](https://i-blog.csdnimg.cn/blog_migrate/39ba400e00cc0506395e560655d0e17c.jpeg)
![f021b878ea23bc092a6385b4d8c62cbc.png](https://i-blog.csdnimg.cn/blog_migrate/dcb62f92c03d4939c929e96c870145c9.jpeg)
从上面sds创建过程可以大概地了解到sds在内存的存储形式
连续的内存, 可依次分为sds header + sds buf(字符串数据) + '0'(终止符)
redis的字符串结构体redisObject的ptr指向就是sds结构
接着来看看struct redisObject(也就是robj)在内存的存储形式,了解完后就能对一个字符串是如何在redis中存储的就会比较清晰了
redisObject(robj)内存存储形式
再来回顾下这个结构
![59c2a519eb6d16e032cb60ec92331080.png](https://i-blog.csdnimg.cn/blog_migrate/c3e8bbf0eed6bdb773c18edbff6cef26.jpeg)
简单看看robj的创建过程
![2e2efff6d27f45ad36ed68c5cef239a5.png](https://i-blog.csdnimg.cn/blog_migrate/42e6afb3141817af14fe42d662d9d7fb.jpeg)
Redis是如何确定字符串的编码类型(robj->encoding)的?
首先从string的set command入手看看
![809e10897b513a1dbcb3d0d7bdc4481d.png](https://i-blog.csdnimg.cn/blog_migrate/9d98204a56068e572df5417a580fa3af.jpeg)
OBJ_ENCODING_INT编码类型
![79feac8336b387ceb99b1638050d3ffc.png](https://i-blog.csdnimg.cn/blog_migrate/ebc7f0298ef4a512c719049e99218f48.jpeg)
OBJ_ENCODING_EMBSTR
![d7a10ede0c638f2d04c68ed7240586a9.png](https://i-blog.csdnimg.cn/blog_migrate/611b19c4c2f423ecc6638cb5a6986081.jpeg)
字符串对象(StringObject)创建过程
![1c53e75349649359d6606a1e2b9f302a.png](https://i-blog.csdnimg.cn/blog_migrate/74a92d2b03b62071a4a523c253cc9a94.jpeg)
1. OBJ_ENCODING_EMBSTR_SIZE_LIMIT是如何计算出来的
看看redis的注释
The current limit of 44 is chosen so that the biggest string object
we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc.
redis使用的内存分配库的申请内存快单位是64byte, 由于embstr的整个redisObject是设计成一块连续内存的(提升读写效率), 因此embstr的整个redisObject大小就被限制在64byte, 那再来计算实际字符串的可用内存大小。
开篇就计算了整个struct redisObject大小是12byte
64 - 12 - 7(sizeof(sdshdr8)) - 1(0) = 44byte
2. Embedded String创建
![bb0a4245525309867c1a1183ca231e8f.png](https://i-blog.csdnimg.cn/blog_migrate/3c0cadfa0da7be8bd8f92b565f50527a.jpeg)
3. Raw String创建
![db27c8bcd99d90959dcfd6c92cc921d2.png](https://i-blog.csdnimg.cn/blog_migrate/7b7eef188a9690fed5713efcdd4195b7.jpeg)
Redis-Cli查看robj type encoding
set abc "1"
type abc -> string
object encoding -> int
set abc "1a"
type abc -> string
object encoding -> embstr
博客相关Github地址
https://github.com/rodbate/blog-code