【IT168技术】Redis是个内存全集的kv数据库,不存在部分数据在磁盘部分数据在内存里的情况,所以提前预估和节约内存非常重要.本文将以最常用的string和zipmap两类数据结构在jemalloc内存分配器下的内存容量预估和节约内存的方法.
先说说jemalloc,传说中解决firefox内存问题freebsd的默认malloc分配器,area,thread-cache功能和tmalloc非常的相识.在2.4版本被Redis引入,在antirez的博文中提到内节约30%的内存使用.相比glibc的malloc需要在每个内存外附加一个额外的4字节内存块,jemalloc可以通过je_malloc_usable_size函数获得指针实际指向的内存大小,这样Redis里的每个key或者value都可以节约4个字节,不少阿.
下面是jemalloc size class categories,左边是用户申请内存范围,右边是实际申请的内存大小.这张表后面会用到.
5 - 8 size class:8
9 - 16 size class:16
17 - 32 size class:32
33 - 48 size class:48
49 - 64 size class:64
65 - 80 size class:80
81 - 96 size class:96
97 - 112 size class:112
113 - 128 size class:128
129 - 192 size class:192
193 - 256 size class:256
257 - 320 size class:320
321 - 384 size class:384
385 - 448 size class:448
449 - 512 size class:512
513 - 768 size class:768
769 - 1024 size class:1024
1025 - 1280 size class:1280
1281 - 1536 size class:1536
1537 - 1792 size class:1792
1793 - 2048 size class:2048
2049 - 2304 size class:2304
2305 - 2560 size class:2560
string
string类型看似简单,但还是有几个可优化的点.先来看一个简单的set命令所添加的数据结构.
一个set hello world命令最终(中间会malloc,free的我们不考虑)会产生4个对象,一个dictEntry(12字节),一个sds用于存储key,还有一个redisObject(12字节),还有一个存储string的sds.sds对象除了包含字符串本生之外,还有一个sds header和额外的一个字节作为字符串结尾共9个字节.
========
51 sds sdsnewlen(const void *init, size_t initlen) {
52 struct sdshdr *sh;
53
54 sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
sds.h
=======
39 struct sdshdr {
40 int len;
41 int free;
42 char buf[];
43
};
根据jemalloc size class那张表,这个命令最终申请的内存为16(dictEtnry) + 16 (redisObject) + 16(“hello”) + 16(“world”),一共64字节.注意如果key或者value的字符串长度+9字节超过16字节,则实际申请的内存大小32字节.