是的
基本上,memcache 按块分配空间而不是按需分配空间,然后将项目存储到块中并手动管理该内存。因此,与按项目分配空间相比,较小的项目可以“使用”大得多的内存。
这个链接比我能解释得更好
https://groups.google.com/group/memcached/browse_thread/thread/8f460034418262e7?pli=1
编辑:添加更多解释
Memcache 通过分配各种大小的slab 来工作。这些板有许多特定尺寸的槽(由板的类别决定)。
假设(并且仅使用我对 Memcache 内部的抽象),假设最小尺寸的 slab 类是 1K。这意味着最小的插槽是 1K。此外,Memcache 一次只会分配 1024 组,即 1MB 内存。假设我们有这样的配置,我们想将一个 1 字节的对象(char 值?)存储到 Memcache 中。假设这需要 5 个字节的内存(4 个字节的密钥?)。在空缓存中,Memcache 将分配一个可以容纳该值的最小尺寸的新平板(1K 个插槽)。因此,存储 5 个字节将导致 Memcache 分配 1MB 内存。
现在,假设你有很多这样的东西。下一个 1023 将是“空闲的”——Memcache 已经分配了内存,因此不需要额外的内存。最后,您存储了 1024 * 5 字节 = ~5KB,但 Memcache 使用了 1MB 来存储它。存储几百万个这样的数据,您可以想象要消耗千兆字节的内存来存储千字节的数据。
这接近于最坏的情况。实际上,如果需要,可以将 Memcache 配置为具有非常小的最小slab 类大小,并且可以扩大或缩小增长因子(slab 类之间的大小差异)。如果您正在缓存数据库查询,您的项目大小可能从几个字节到几个 KB,页面内容甚至可以达到 MB。
这是关键点Memcache 不会回收内存或清理slab(新版本现在确实有这个功能,因为它对性能有很大影响,但传统上,这就是Memcache 的工作方式)。
假设您的系统已经愉快地运行和缓存了几天。您有数百个不同尺寸的板。您在不重置缓存的情况下将新的页面缓存策略部署到您的应用程序。现在不是缓存整个页面,而是缓存页面的一部分。您已将缓存模式从存储大量 ~1MB 对象更改为存储大量 ~10KB 对象。这就是我们遇到麻烦的地方。 Memcache 分配了一堆保存大约 1MB 对象的平板。您以前从未缓存过许多 10KB 的对象。有 10KB 插槽的slab 很快就被填满了,但是现在你有一大堆已分配的slab,其中包含1MB 的对象,这些对象没有被使用(没有其他东西那么大)。 Memcache 不会将您的 10KB 对象放入 1MB 插槽中(即使这样做了,也不会在很长时间内发挥作用)。它需要获得更多容纳 10KB 对象的slab,但它不能,因为您所有的内存都已分配给容纳 1MB 对象的slab。结果是您可能会在slab 中分配千兆字节的内存来保存1MB 的对象,这些对象在您的10KB 槽slab 已满时处于空闲状态。在这种情况下,尽管有 GB 空闲,您仍将开始从 10KB 插槽平板中逐出项目。
这是一个冗长的、做作的、极端的例子。您的缓存策略很少会发生如此明显或如此显着的变化。 slab-classes 的默认增长因子是 1.25,因此您将拥有具有 1KB 插槽、1.25KB 插槽、1.5KB 插槽等的slab。这个概念成立——如果您大量使用特定大小的slab 并且模式发生变化(sql查询返回更多对象?网页变大?在表格中添加一列,将缓存的响应向上移动到一个平板类?等等)然后你会得到一堆“错误”大小的平板,你可以拥有尽管有千兆字节的“未使用”空间,但“无处”存储东西。
如果您被驱逐,可以通过 telnet 进入 Memcache 并找出导致驱逐的平板。通常,缓存重置(是的,清空所有内容)可以解决问题。这是有关如何获取统计信息的参考。
http://lzone.de/articles/memcached.htm