Memcached的内存分配器是如何工作的?为什么不适用malloc/free!?为何要使用slabs?
参考回答
Memcached 的内存分配器通过 Slab Allocation 机制进行内存管理,避免了直接使用 malloc/free
所带来的内存碎片和性能问题。
Slab Allocation 通过将内存预划分为固定大小的块(chunk),并根据数据大小分配到合适的块中,从而实现高效的内存管理和分配。
详细讲解与拓展
1. 为什么 Memcached 不直接使用 malloc/free
?
- 内存碎片问题:
- 如果使用
malloc/free
动态分配内存,缓存的数据大小各异,会导致内存碎片增多(即未使用的小内存块分布在内存中,无法有效利用)。 - 内存碎片会降低内存利用率,进而影响缓存的容量和性能。
- 如果使用
- 性能问题:
- 动态分配内存涉及频繁的系统调用,
malloc
的分配和free
的释放需要维护复杂的数据结构(如空闲链表),这些操作耗时较多,不适合高并发、高性能场景。
- 动态分配内存涉及频繁的系统调用,
- 不确定性:
- 动态内存分配的效率会随着系统状态和内存碎片的增加而变化,无法提供稳定的性能。
2. Slab Allocation 的内存管理机制
Slab Allocation 的核心思想是:预分配内存并分层管理,以减少内存碎片和动态分配开销。
- 内存划分:
- 启动 Memcached 时,系统会根据指定的总内存容量(如 1 GB),将内存分为多个 slab。
- 每个 slab 被划分为固定大小的内存块(chunk),不同 slab 的 chunk 大小不同(如 64 字节、128 字节、256 字节等)。
- 分配过程:
- 每次需要存储数据时,根据数据的大小选择一个合适的 slab,将数据存储到该 slab 中的 chunk。
- 每个 slab 中的 chunk 大小是固定的,chunk 内部无法存储多个 item,一个 chunk 只能存储一个 item。
- 管理策略:
- 如果某个 slab 的 chunk 被使用完,Memcached 会动态扩展 slab 的容量,或者根据 LRU 策略清理旧数据。
3. 使用 Slab Allocation 的优点
- 减少内存碎片:
- 由于 chunk 的大小是固定的,且每个 slab 中的 chunk 尺寸相同,能有效避免因数据大小不一致而导致的内存碎片。
- 提高内存利用率:
- 每个 slab 针对一类数据大小进行优化,确保小数据不会浪费大块的内存。
- 性能稳定:
- 预分配内存后,不再需要频繁调用
malloc/free
,减少了系统调用的开销,提高了分配效率。
- 预分配内存后,不再需要频繁调用
- 可预测的分配效率:
- Slab Allocation 的分配和回收速度较快,不会因系统状态的变化而波动,能提供一致的性能。
4. Slab Allocation 的工作流程
- 初始化:
- 启动时,将分配的总内存分为多个 slab,每个 slab 中的 chunk 尺寸递增,例如:64B、128B、256B 等。
- 分配数据:
- 根据存储数据的大小,选择最小能容纳该数据的 chunk。如果数据大小为 100 字节,则会分配到 128B 的 slab 中。
- 回收内存:
- 当某个 slab 的 chunk 被释放时,该 chunk 会被标记为空闲,可以重新分配给新数据。
5. Slab Allocation 的限制
- 可能造成内存浪费:
- 由于每个 chunk 的大小固定,数据大小不足 chunk 的容量时,会造成浪费。例如,存储 65 字节的数据需要一个 128 字节的 chunk。
- 数据迁移复杂:
- Slab Allocation 固定了每个 slab 的 chunk 大小,数据无法轻易迁移到其他 slab。
举例说明
假设 Memcached 有 512 MB 内存分配,总共划分为 5 个 slab:
Slab ID | Chunk 大小 | Slab 数量 | 总内存占用 |
---|---|---|---|
Slab 1 | 64B | 10,000 | 640 KB |
Slab 2 | 128B | 8,000 | 1 MB |
Slab 3 | 256B | 6,000 | 1.5 MB |
Slab 4 | 512B | 4,000 | 2 MB |
Slab 5 | 1024B | 2,000 | 2 MB |
如果存储一个 200 字节的数据:
1. Memcached 会将其分配到 256B 的 slab。
2. 即使只使用了 200 字节,剩余的 56 字节也会浪费,称为 内存对齐开销。
总结
Memcached 使用 Slab Allocation 代替 malloc/free
是为了减少内存碎片、优化性能和提高内存分配的效率。虽然 Slab Allocation 有一定的内存浪费,但它在高性能和高并发场景下表现优异。通过合理的内存划分,Memcached 在性能和内存利用率之间找到了平衡,是其高效运行的重要基础。