Redis SDS 的惰性删除主要通过 sdsRemoveFreeSpace 函数实现,其核心是在特定场景下移除 SDS 字符串末尾的未使用空间(free space),以优化内存和磁盘使用效率。 以下是具体分析:
1. SDS 惰性删除的触发场景Redis 不会在每次字符串缩短后立即释放未使用空间,而是通过以下场景触发惰性删除:
- RDB 持久化在生成 RDB 快照时,Redis 会遍历数据库并写入磁盘。为减少磁盘占用和提高 I/O 效率,写入前会调用 sdsRemoveFreeSpace 清除 SDS 的未使用空间,使数据更紧凑。
- AOF 重写AOF 重写生成新文件时,Redis 会优化 SDS 字符串,移除未使用空间以缩小文件体积。
- 内存压力回收当内存接近上限或触发 freeMemoryIfNeeded 时,Redis 会检查 SDS 的未使用空间并调用 sdsRemoveFreeSpace 释放内存。
- 键值对删除或过期删除键值对时,Redis 可能在释放 SDS 前调用 sdsRemoveFreeSpace,确保仅释放实际使用的内存。
- 特定命令或模块自定义命令或模块可能主动调用 sdsRemoveFreeSpace 以即时优化内存。
2. SDS 设计特性与惰性删除的关系SDS 的惰性删除机制依赖于其设计特性:
- 空间预分配SDS 在字符串增长时预分配额外空间(如 len 的一倍),减少频繁内存分配的开销。但缩短字符串时,未使用空间(free)会保留,需通过惰性删除释放。
- 未使用空间跟踪SDS 通过 free 字段记录未使用空间大小。惰性删除时,sdsRemoveFreeSpace 会根据 len 重新分配内存,仅保留必要空间。
- 高效修改操作追加内容时,若 free 不足则扩容;删除内容时,len 减小而 free 增加。惰性删除在后续场景中处理这些未使用空间。
3. sdsRemoveFreeSpace 的执行流程该函数通过以下步骤移除未使用空间:
- 调整容量根据当前 len 重新分配内存,确保仅存储有效字符。
- 更新结构修改 SDS 的 alloc(总容量)和 buf(字符数组指针)字段,匹配新内存布局。
- 释放内存归还原 SDS 中未使用的内存块,避免浪费。
4. 惰性删除的优势- 性能优化避免频繁内存分配/释放,降低操作开销。例如,字符串缩短后不立即缩容,减少后续追加时的扩容次数。
- 资源高效利用在内存紧张或持久化时集中释放未使用空间,平衡实时性能与资源利用率。
- 数据紧凑性持久化前清理未使用空间,减少磁盘占用和 I/O 负载。
5. 与空间预分配的协同SDS 的空间预分配策略(如增长时分配额外空间)与惰性删除形成互补:
- 预分配提升增长效率通过预留空间减少频繁扩容,适合高频追加场景。
- 惰性删除优化缩短操作缩短字符串后暂不释放空间,待触发条件(如持久化)时统一处理,避免性能波动。
6. 实际应用示例总结:Redis SDS 的惰性删除通过 sdsRemoveFreeSpace 在关键场景(如持久化、内存回收)下移除未使用空间,结合空间预分配策略,实现了内存使用的高效性与操作性能的平衡。