标签:int col img 简单 长度 pre 过滤 -- 取字符串
Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组,以下简称 C 字符串), 而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型, 并将 SDS 用作 Redis 的默认字符串表示。
在 Redis 里面, C 字符串只会作为字符串字面量(string literal), 用在一些无须对字符串值进行修改的地方, 比如打印日志.
当 Redis 需要的不仅仅是一个字符串字面量, 而是一个可以被修改的字符串值时, Redis 就会使用 SDS 来表示字符串值
struct sdshdr { // 记录 buf 数组中已使用字节的数量, 不包括 ‘\0‘ 的长度 // 等于 SDS 所保存字符串的长度 int len; // 记录 buf 数组中未使用字节的数量 int free; // 字节数组,用于保存字符串 char buf[]; };
buf [ ] 除了保存字符串的字符外, 还会在末尾保存一个空字符 ‘\0‘ , 空字符不计算在 len 属性之中.
遵循空字符结尾的好处是可以重用一部分C字符串的函数.
C字符串不记录自身的长度信息, 获取字符串长度时会遍历字节数组, 直到遇到空字符为止. 复杂度为 O(N)
SDS直接通过 len 属性获取字符串长度. 复杂度为O(1)
C字符串不记录自身长度, 修改字符串时不会判断本身是否拥有足够的内存空间, 当内存空间不足时, 则会造成缓冲区的溢出.
SDS对字符串进行修改时,先检查内存空间是否满足修改的需要, 若不满足, 则自动扩展SDS的内存空间. 所以使用SDS既不需要手动修改内存空间的大小, 也不会出现缓冲区溢出的情况.
第一次创建字符串对象时, SDS不会分配冗余空间, 即 len = 0
当SDS的API修改SDS时, 则会为其分配冗余空间.
SDS的API缩短SDS的字符串时, 不会立即使用内存分配回收缩短后多出来的字节, 而是记录在 free 属性中, 并等待将来使用.
C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据。
SDS的API都是二进制安全的.所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、或者假设,数据在写入时是什么样的,它被读 取时就是什么样。
这也是我们将SDS的buf属性称为字节数组的原因——Redis不是用这个数组来保存字符,而是用它来保存一系列二进制数据。
传送门 : Redis 数据编码方式详解
为什么会有不同的编码方式,为了解释这种现象,我们首先来了解一下 Redis 对象头结构体,所有的 Redis 对象都有下面的这个结构头:
struct RedisObject { int4 type; // 4 bits int4 encoding; // 4 bits int24 lru; // 24 bits int32 refcount; // 4 bytes void *ptr; // 8 bytes,64-bit system } robj;
不同的对象具有不同的类型 type(4bit),同一个类型的 type 会有不同的存储形式 encoding(4bit),为了记录对象的 LRU 信息,使用了 24 个 bit 来记录 LRU 信息。
每个对象都有个引用计数,当引用计数为零时,对象就会被销毁,内存被回收。ptr 指针将指向对象内容 (body) 的具体存储位置。
这样一个 RedisObject 对象头需要占据 16 字节的存储空间。
从Redis 3.0版本开始字符串引入了EMBSTR编码方式,长度小于OBJ_ENCODING_EMBSTR_SIZE_LIMIT(39)的字符串将以EMBSTR方式存储。
EMBSTR方式的意思是 embedded string ,字符串的空间将会和redisObject对象的空间一起分配,两者在同一个内存块中。
Redis中内存分配使用的是jemalloc,jemalloc分配内存的时候是按照 8,16,32,64 作为chunk的单位进行分配的。
为了保证采用这种编码方式的字符串能被jemalloc分配在同一个chunk中,该字符串长度不能超过64,
故字符串长度限制OBJ_ENCODING_EMBSTR_SIZE_LIMIT = 64 - sizeof(‘0‘) - sizeof(robj)为16 - sizeof(struct sdshdr)为8 = 39。
采用这个方式可以减少内存分配的次数,提高内存分配的效率,降低内存碎片率。
从len字段可以判断并不不依赖于‘0‘,故可以用与保存二进制对象。
从free字段可以判断其空间分配是采用预分配的方式,避免字符串修改时频繁分配释放内存。
INT编码方式以整数保存字符串数据,仅限能用long类型值表达的字符串。
当robj中的LRU值没有意义的时候(实例没有设置maxmemory限制或者maxmemory-policy设置的淘汰算法中不计算LRU值时),
0-10000之间的OBJ_ENCODING_INT编码的字符串对象将进行共享。
标签:int col img 简单 长度 pre 过滤 -- 取字符串
原文地址:https://www.cnblogs.com/virgosnail/p/9533233.html