C++ Redis集合中的成员占用了多少字节

C++ Redis集合中的成员占用了多少字节,c++,memory,nosql,redis,hashset,C++,Memory,Nosql,Redis,Hashset,我使用Redis作为内存哈希集。在我向一个集合中插入1M个8字节的密钥(二进制)后,我发现Redis使用的内存约为100M,这意味着单个成员需要100字节?为什么? 或者如何配置Redis以节省内存使用。如果不知道集合中每个成员的底层结构,很难说。但是,如果您正在存储键/值,则每个成员都在存储键和值(即使值为空,也需要为其保留引用) 对于键的快速查找,底层结构很可能是一棵树,这意味着它需要为每个成员在树中存储指向左、右下降节点的左、右(或红色/黑色)指针。在64位系统中,这些指针每个为8字节 为

我使用Redis作为内存哈希集。在我向一个集合中插入1M个8字节的密钥(二进制)后,我发现Redis使用的内存约为100M,这意味着单个成员需要100字节?为什么?


或者如何配置Redis以节省内存使用。

如果不知道集合中每个成员的底层结构,很难说。但是,如果您正在存储键/值,则每个成员都在存储键和值(即使值为空,也需要为其保留引用)

对于键的快速查找,底层结构很可能是一棵树,这意味着它需要为每个成员在树中存储指向左、右下降节点的左、右(或红色/黑色)指针。在64位系统中,这些指针每个为8字节

为了有效地分配和取消分配键/值对,每个成员节点可以具有指示其大小和可用性(已分配、已删除)的数据成员,以便可以从内存池中分配每个成员节点,并进行垃圾收集或标记为已删除和重新使用。每次填充前一个池时,典型的池分配会将池大小加倍,以最小化堆争用,这对于多线程应用程序的性能非常重要。您的100万内存可能包含50万个未使用(但已分配)的密钥持有者


为什么要节省内存使用量?您是否计划存储数十亿个哈希键?

首先,您应该详细说明此类问题的设置,因为内存布局取决于操作系统、内存分配器、平台和Redis版本

在使用Redis2.4的64位Linux机器上,一组8字节的1M项密钥消耗87MB

与键的大小相比,它似乎要大得多,但是任何支持对其项的有效访问的动态数据结构都会带来开销。项目越小,开销越大

在Redis中,大型集合使用单独的链接哈希表实现。每个条目由以下结构表示:

typedef struct dictEntry {
    void *key;
    void *val;
    struct dictEntry *next;
} dictEntry;
struct sdshdr {
    int len;
    int free;
   char buf[];
};
因为内存分配器(jemalloc)不支持24字节类,所以使用32字节。在此结构中,val设置为NULL(这是一个集合),关键点指向定义如下的对象:

typedef struct redisObject {
    unsigned type:4;
    unsigned storage:2;     /* REDIS_VM_MEMORY or REDIS_VM_SWAPPING */
    unsigned encoding:4;
    unsigned lru:22;        /* lru time (relative to server.lruclock) */
    int refcount;
    void *ptr;
} robj;
这个结构只需要16个字节。它指向由该可变长度结构表示的关键数据本身:

typedef struct dictEntry {
    void *key;
    void *val;
    struct dictEntry *next;
} dictEntry;
struct sdshdr {
    int len;
    int free;
   char buf[];
};
键的大小为8字节,加上一个nul字符,因此每个键的大小为17字节。下一个分配类是带有jemalloc的32字节,因此此结构将占用32字节

总之,每个项目的成本为:32+16+32=80字节。他们有100万人。为哈希表本身添加一些空间(包含至少1M个指向dictEntry结构的指针),得到的结果非常接近我们在这个平台上可以测量到的87MB

优化一个大型集合的内存占用并不是一件小事。当集合很小(默认情况下少于512项)并且键实际上是整数时,Redis将执行优化。请参阅更多信息


一种可能的优化方法是增加set max intset entries参数,并将集合拆分为多个部分。例如,可以对项目键进行散列,以将项目分布在不同的集合上。除了myset,还有myset:0、myset:1、myset:2。。。迈斯特:不。要检查给定项是否为集合,将在键上计算哈希值以找到正确的myset:X条目,然后检查此特定条目。其目的是将所有这些集合的大小保持在set max intset entries参数以下,以便从内存优化中获益。当然,这会使在集合上执行的所有操作更加复杂,因此这实际上是复杂性和内存占用之间的折衷。

这是完全错误的。Redis中的集合存储为哈希表,而不是树。Redis没有池分配:它主要依赖于优秀的jemalloc通用分配器(从2.4版开始)。Redis中没有垃圾收集:而是使用引用计数。感谢您的更正。在我的辩护中,我只是猜测Redis使用的内部结构,我发现你上面的详细回答很有趣,很有启发性。