使用的底层结构为简单动态字符串(Simple Dynamic String SDS)。
typedef char *sds;
struct sdshdr {
int len;
int free;
char buf[];
};
简单动态字符串内存长度:
len:记录buf已使用的长度,len长度为4byte;
alloc:记录buf实际分配的长度,alloc长度为4byte;
buf:字节数组,保存实际数据,“ ”表示数据结束,额外增加1个字节开销。
String类型除了SDS内存使用外,还有RedisObject结构体。
RedisObject结构体使用8byte存储元数据,使用8byte存储数据指针,数据指针指向具体数据所在位置。
Redis针对不同的数据类型,做了一些优化:
1.如果是Long类型整数,ptr为整数数据,非指针,目的是为了节省内存,这种内存布局方式称为int编码方式;
2.如果是字符串类型,并且长度小于或等于44byte时,RedisObject中的元数据、ptr、SDS为一块连续内存,目的为了避免内存碎片,这种内存布局方式称为embstr编码方式;
3.如果字符串类型大于44byte,ptr指向SDS内存空间,这种内存布局方式称为raw编码方式。
int编码、embstr编码、raw编码方式结构如下:
Redis核心技术-数据结构1-底层结构中说的key和value存储在哈希表dictEntry结构体中,dictEntry结构体需要24byte,但是由于jemalloc内存分配方式规则,dictEntry实际内存为32byte。内存结构如下:
Redis使用jemalloc库分配内存,jemalloc分配内存时,根据申请内存字节数N,计算比N大的字节数S,S取值最接近2的次方数。
例如N=24,S取值2的5次方=32。类似JVM中的内存大小分配。
由此可以计算出一个key和value最少需要多大内存?
key和value都是Long整数,都使用int编码,需要64byte,其中dictEntry32byte(24byte+8byte填充)、key值16byte、value值16byte;
typedef struct redisObject {
// 对象的类型,REDIS_STRING,REDIS_LIST,REDIS_HASH,
//REDIS_SET,REDIS_ZSET
unsigned type:4;
// 未使用的两个位
unsigned notused:2;
// 编码的方式,Redis 为了节省空间,提供多种方式来保存一个数据
// 例如:int编码、embstr编码、raw编码
unsigned encoding:4;
// 当内存紧张,淘汰数据的时候用到
unsigned lru:22;
// 引用计数
int refcount;
// 数据指针
void *ptr;
} robj;
RedisObject 的内部组成包括了 type,、encoding,、lru 和 refcount 4 个元数据,以及 1 个*ptr指针。
参数说明:
lru:lru记录此对象最后一次访问的时间。
当redis内存回收算法设置为volatile-lru或者allkeys-lru时候redis会优先释放最久没有被访问的数据。
refcount:用于共享计数,类似于jvm的引用计数垃圾回收算法,当refcount为0时,表示没有其它对象引用,可以进行释放此对象。
ptr 指针:ptr 指针是指向对象的底层实现数据结构。
查看key type:
> set testkey1 test OK > type testkey1 string
查看key encoding:
> set testkey1 test OK > object encoding testkey1 embstr > set testkey2 7 OK > object encoding testkey2 int
参考:
https://www.cnblogs.com/monkey-code/p/13157908.html



