之前的SDS结构定义
struct sdshdr {
unsigned int len;
unsigned int free;
char buf[];
};
sizeof:8字节
提出问题?
不同长度的字符串是否有必要占用相同大小的头部?
如何区分短字符串、长字符串、更长字符串呢?
对于短字符串而言,头部是否还有更节省内存的方法呢?
redis3.2之后,对SDS进行了优化改进
1、新增一个flags字段来标识类型(属于哪一种字符串)
2、对于更节省内存的方法就是使用位,一个字节是八位,那么要区分小于1字节、1字节、2字节、
4字节、8字节五种类型,至少需要3位来存储类型,那么剩下的5位可以存储长度(可以满足长度小于
32的短字符串)
3、下面是用来存储长度小于32的短字符串的结构:
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
sizeof:1字节
长度大于32的分为下面四种
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
sizeof:3字节
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
sizeof:5字节
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
sizeof:9字节
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
sizeof:17字节
这里解释一下__attribute__ ((__packed__)):告诉编译器取消结构在编译过程中的优化对
齐,按照实际占用字节数进行对齐,是 GCC 特有的语法。由按原来结构体内所有变量大小的最小
公倍数做字节对齐,变为了按1字节对齐;这样,节省内存,sds返回给上层的就是buf指针。
下面是对于类型的宏定义:
#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
有哪些操作呢?
创建字符串:sdsnewlen
1、首先根据initlen的长度返回sds的类型,这里需要注意如果是空字符,会被转换为sdshdr8
2、根据类型算出该结构的大小
3、根据结构的大小+字符串的大小+1(\0)分配空间,返回该地址的指针