元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
Redis核心
▶
数据结构
字符串实现
哈希表实现
列表实现
集合实现
有序集合实现
▶
内存管理
内存分配策略
淘汰算法
▶
持久化
▶
RDB机制
快照生成原理
文件格式解析
▶
AOF机制
命令追加策略
重写过程分析
▶
高可用
▶
主从复制
SYNC原理
增量复制
▶
哨兵机制
故障检测
领导选举
▶
高级特性
▶
事务系统
ACID实现
WATCH原理
▶
Lua脚本
沙盒环境
执行管道
▶
实战问题
▶
缓存问题
缓存雪崩
缓存穿透
缓存击穿
缓存预热
▶
数据一致性
读写一致性
双写一致性
▶
性能优化
大key处理
热点key优化
发布时间:
2025-03-22 10:38
↑
☰
# Redis内存分配策略 ## 引言 Redis作为内存数据库,内存管理是其核心功能之一。本文将深入探讨Redis的内存分配策略,包括内存分配器的选择、内存管理机制以及优化方案,帮助读者更好地理解Redis的内存管理机制。 ## 内存分配器 ### jemalloc Redis默认使用jemalloc作为内存分配器,这是因为jemalloc具有以下优势: 1. **内存碎片控制** - 使用多个内存池管理不同大小的内存块 - 通过规整的内存分配策略减少碎片 - 支持内存碎片的合并和重用 2. **性能优势** - 采用线程缓存,减少锁竞争 - 使用红黑树管理内存块,提高分配效率 - 支持批量内存分配和释放 ### 内存分配器的选择 ```c // 编译时可以选择不同的内存分配器 #if defined(USE_JEMALLOC) #define MALLOC jemalloc_malloc #define FREE jemalloc_free #elif defined(USE_TCMALLOC) #define MALLOC tcmalloc_malloc #define FREE tcmalloc_free #else #define MALLOC malloc #define FREE free #endif ``` ## 内存管理机制 ### 1. 内存池化管理 ```c typedef struct { void *ptr; // 内存块指针 size_t size; // 内存块大小 int used; // 使用标志 } zmalloc_entry; typedef struct { zmalloc_entry *entries; // 内存块数组 int size; // 内存池大小 int used; // 已使用数量 pthread_mutex_t lock; // 互斥锁 } zmalloc_pool; ``` ### 2. 内存对齐 ```c // 计算对齐后的大小 size_t zmalloc_size_align(size_t size) { return (size + (sizeof(long) - 1)) & ~(sizeof(long) - 1); } // 分配对齐的内存 void *zmalloc_align(size_t size) { void *ptr; size = zmalloc_size_align(size); if ((ptr = malloc(size + PREFIX_SIZE)) == NULL) return NULL; *((size_t*)ptr) = size; update_zmalloc_stat_alloc(size + PREFIX_SIZE); return (char*)ptr + PREFIX_SIZE; } ``` ### 3. 内存前缀 Redis为每个分配的内存块添加前缀信息: ```c // 内存块前缀结构 typedef struct { size_t size; // 实际分配的大小 char data[]; // 用户数据 } zmalloc_block; // 获取内存块大小 size_t zmalloc_get_rss(void) { size_t rss; zmalloc_block *block; block = (zmalloc_block *)((char*)ptr - sizeof(size_t)); rss = block->size; return rss; } ``` ## 内存分配策略 ### 1. 动态字符串分配 ```c // 字符串空间预分配 sds sdsMakeRoomFor(sds s, size_t addlen) { void *sh, *newsh; size_t avail = sdsavail(s); size_t len, newlen; if (avail >= addlen) return s; len = sdslen(s); newlen = len + addlen; // 预分配策略 if (newlen < SDS_MAX_PREALLOC) newlen *= 2; else newlen += SDS_MAX_PREALLOC; newsh = s_realloc(sh, sizeof(struct sdshdr)+newlen+1); return newsh; } ``` ### 2. 哈希表扩容 ```c // 渐进式rehash的内存分配 int dictRehash(dict *d, int n) { if (!dictIsRehashing(d)) return 0; while (n-- && d->ht[0].used != 0) { dictEntry *de, *nextde; // 分配新的哈希表空间 if (d->ht[1].size == 0) { d->ht[1].table = zcalloc(sizeof(dictEntry*)*d->ht[1].sizemask+1); if (d->ht[1].table == NULL) return DICT_ERR; } // rehash过程 // ... } return 1; } ``` ### 3. 列表节点分配 ```c // 创建新的列表节点 listNode *listCreateNode(list *list, void *value) { listNode *node; if ((node = zmalloc(sizeof(*node))) == NULL) return NULL; node->value = value; return node; } ``` ## 内存优化策略 ### 1. 共享对象池 ```c // 初始化整数共享对象 void createSharedObjects(void) { int j; for (j = 0; j < OBJ_SHARED_INTEGERS; j++) { shared.integers[j] = createObject(OBJ_STRING, (void*)(long)j); shared.integers[j]->encoding = OBJ_ENCODING_INT; } } ``` ### 2. 压缩编码 ```c // 使用ziplist压缩列表 unsigned char *ziplistNew(void) { unsigned int bytes = ZIPLIST_HEADER_SIZE+ZIPLIST_END_SIZE; unsigned char *zl = zmalloc(bytes); if (zl == NULL) return NULL; // 初始化ziplist头部 ZIPLIST_BYTES(zl) = intrev32ifbe(bytes); ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE); ZIPLIST_LENGTH(zl) = 0; zl[bytes-1] = ZIP_END; return zl; } ``` ### 3. 内存碎片整理 ```c // 内存碎片整理配置 struct redisServer { // ... int active_defrag_running; // 碎片整理是否运行中 int active_defrag_threshold_lower; // 启动阈值 int active_defrag_threshold_upper; // 停止阈值 int active_defrag_ignore_bytes; // 忽略的碎片大小 int active_defrag_cycle_min; // 最小CPU时间比 int active_defrag_cycle_max; // 最大CPU时间比 }; ``` ## 内存监控 ### 1. 内存使用统计 ```c // 获取内存使用信息 void getMemoryInfo(struct redisMemOverhead *info) { size_t mem_total, mem_used, mem_fragmentation; // 计算总内存 mem_total = zmalloc_get_rss(); // 计算已使用内存 mem_used = zmalloc_used_memory(); // 计算碎片率 mem_fragmentation = (float)mem_total/mem_used; // 填充信息结构 info->total = mem_total; info->used = mem_used; info->fragmentation = mem_fragmentation; } ``` ### 2. 内存警告机制 ```c // 内存警告检查 void checkMemoryWarnings(void) { int used_memory_pct; // 计算内存使用百分比 used_memory_pct = (zmalloc_used_memory() * 100) / server.maxmemory; // 发送警告 if (used_memory_pct > server.memory_warning_limit) { serverLog(LL_WARNING,"Memory usage warning: %d%%", used_memory_pct); } } ``` ## 最佳实践 ### 1. 内存配置 ```conf # 设置最大内存 maxmemory 2gb # 设置内存策略 maxmemory-policy allkeys-lru # 设置内存采样率 maxmemory-samples 5 ``` ### 2. 内存优化建议 1. **合理设置maxmemory** - 预留系统内存 - 考虑内存碎片率 - 定期监控内存使用 2. **使用合适的数据结构** - 小数据优先使用压缩编码 - 大数据考虑分片存储 - 及时清理过期数据 3. **内存碎片优化** - 开启自动内存碎片整理 - 设置合理的碎片整理阈值 - 监控碎片率变化 ## 总结 Redis的内存分配策略是一个复杂而精密的系统,通过jemalloc内存分配器、内存池化管理、对象共享等机制,实现了高效的内存管理。在实际应用中,需要根据具体场景选择合适的内存配置和优化策略,同时做好内存监控,以确保Redis的稳定运行。