赞
踩
Redis使用32bit进行编译,内部所有的数据结构使用的指针占用空间会比64bit少一半,如果Redis可使用的内存在4GB以内可以用32bit编译。
当Redis数据结构中的数据量比较少时,将会使用紧凑存储形式压缩,例如HashMap原本是一个二维结构(数组+链表),但是内部元素较少时,使用二维结构会比较浪费空间,
此时可以直接用一维数组进行存储,并且此刻使用数组进行遍历查找可以比HashMap本身查找更快。
如下图所示,ziplist是一个紧凑的字节数组结构,每个元素都是紧挨着的。
如果ziplist中存储的是hash结构,那么key和value会作为两个entry被相邻存储,如下面demo所示,对hello这个字典结构增加了
- 127.0.0.1:6379> hset hello a 1
-
- (integer) 1
-
- 127.0.0.1:6379> hset hello b 2
-
- (integer) 1
-
- 127.0.0.1:6379> object encoding hello
-
- "ziplist"
- 复制代码
如果存储的是zset结构,那zset的value和score会作为两个entry相邻存储。
- 127.0.0.1:6379> zadd world 1 a
-
- (integer) 1
-
- 127.0.0.1:6379> zadd world 2 b
-
- (integer) 1
-
- 127.0.0.1:6379> object encoding world
-
- "ziplist"
- 复制代码
可以看到,数据量很小的时候,不管是hash还是zset,实际的存储结构都是ziplist。
intset是一个紧凑的整数数组结构,专门用于存储整数元素并且元素个数较少的情况。
如果新加入的整数可以用uint16表示,那么encoding就用uint16表示,如果不够就是用uint32, 还不够就是uint64。
- 127.0.0.1:6379> sadd hello 1 2 3
-
- (integer) 3
-
- 127.0.0.1:6379> object encoding hello
-
- "intset"
-
- 复制代码
如果set中存储字符串,那么intset将立刻变成hashtable。
- 127.0.0.1:6379> sadd hello hi
-
- (integer) 1
-
- 127.0.0.1:6379> object encoding hello
-
- "hashtable"
- 复制代码
当数据结构中的元素触发条件时,数据结构将晋升为标准数据结构。
- hash-max-ziplist-entries 512
- 复制代码
- hash-max-ziplist-value 64
- 复制代码
- list-max-ziplist-entries 512
- 复制代码
- list-max-ziplist-value 64
- 复制代码
- zset-max-ziplist-entries 128
- 复制代码
- zset-max-ziplist-value 64
- 复制代码
- set-max-intset-entries 512
- 复制代码
如下demo,可以看到hash的元素超过512时变成了hashtable,之前都是ziplist。
同样,当key/value超过64位时, 也发生了变化。
redis并不会将空闲的内存及时还给操作系统,因为操作系统将内存划分为一个一个的页作为基本单位,只要页上还留有一个key,那么这个页就不能被回收,
如果你发现删除了很多的key,内存并没有降下来,这说明还有很多零散的key分散在这些页中导致内存无法回收,如果使用flushdb,内存将会被回收,因为该操作将所有页上的key都删除了。
redis无法保证立即回收已删除的key的内存,但是它会重复利用这些内存,当有新数据来时,redis将会分配在这些空闲的内存上。
redis自身没有实现内存分配管理,而是交给了第三方内存分配库实现,目前redis默认使用的是jemalloc库管理内存,也可以切换为tcmalloc,前者性能要比后者稍好一些。
通过 info memory 指令可以看到redis正在使用的mem_allocator是什么。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。