理解散列实现及其在 Redis 中的内存

Kar*_*all 5 memory hash hashmap redis

从文档中我们知道 redis 对某个范围内的数据进行压缩(默认为 512)。如果哈希范围超过 512,则内存差异将是 10 倍。

我对从 1 到 512 的哈希值做了一个小实验,发现了一些有趣的模式。

此图表示 1000 个哈希所占用的内存(以 KB 为单位),每个哈希包含 1 到 512 的条目。

在此处输入图片说明

正如您在此图中所见。在某些时间间隔内存在陡峭。我了解 redis 中的哈希实现也遵循一些逻辑,用于在达到某个范围时扩展大小,而不是为每个新条目增加它。从数字来看,它并没有始终遵循加倍模式,但从 215 到 216,它确实加倍了,4 MB 到 8 MB。从 420 到 421,它几乎增加了 8 MB 到 12 MB 的一半。在 215 度以内的陡坡中,我看不到它在 1/4、1/5 和 1/6 之间变化的任何模式。

根据我的观察,以下是我的问题:

  1. 有人可以解释一下 hashmap 在内存和调整大小方面的内部情况吗?调整大小时遵循的逻辑是什么?
  2. 如果我不得不为了再存储一个 215 到 216 的条目而释放双倍内存,为什么我不能限制我的应用程序的哈希值始终小于 215,除非并且直到系统最多需要它。
  3. 假设我想存储 100 万个散列,每个散列由 250 个值组成,我需要 800MB。如果我将它们分成 2 个 125 个值的散列,即 125 个值的 200 万个散列,我需要 500MB。通过这种方式,我节省了 300 MB,这是巨大的!!。这个计算对吗?在这种情况下我错过了什么吗?

提前致谢

sel*_*ish 4

由于redis中不断有1000个key,每个hash key中只有字段号发生变化,而你的字段号低于512,所以这种现象只是jemalloc造成的。

这是我使用 libc 作为 mem_allocator 时的行为:

您可以通过以下方式重新制作您的redis:

make MALLOC=libc
Run Code Online (Sandbox Code Playgroud)

再次运行测试,看看会得到什么。

回答您的问题:

  1. 有人可以向我解释一下 hashmap 在内存和调整大小方面的内部情况吗?调整大小时遵循的逻辑是什么?

    如前所述,您遇到的情况与redis本身无关。Jemalloc这样做是为了提高效率

  2. 如果我必须释放双倍的内存来存储一个 215 到 216 的条目,为什么我不能限制我的应用程序的哈希值始终小于 215,除非系统最需要它。

    当然只要能限制字段个数就可以

  3. 假设如果我想存储 100 万个哈希值,每个哈希值由 250 个值组成,我需要 800MB。如果我将它们分成 2 个包含 125 个值的哈希值,即 200 万个包含 125 个值的哈希值,我需要 500MB。这样我就节省了 300 MB,这是巨大的!!这个计算对吗?在这种情况下我错过了什么吗?

    我认为这不是正确的方法。这样做也许可以节省一些内存。然而,缺点是:当你将 100 万个哈希拆分为 200 万个时,redis 会进行重新哈希(这会占用你一些空间),并且会花费你更多的时间来找到一个键,因为这会导致更多的哈希冲突的机会。