我在 node.js 中有一个非常大的对象集合(数百万),我需要将它们保存在内存中以进行缓存(它们保存在几个全局哈希对象中)。每个哈希集合存储大约 750k 个键。
为了将 GC 保持在最低限度,我想找出存储这些项目的最佳方式。将这些项目拆分成成千上万的哈希值会更好吗?我应该根本不使用哈希吗?有没有办法让它们完全离开堆,这样它们就不会被 GC 检查(如果是这样,我会怎么做)?
我在 node.js 中有一个非常大的对象集合(数百万),我需要将它们保存在内存中以进行缓存(它们保存在几个全局哈希对象中)。每个哈希集合存储大约 750k 个键。
为了将 GC 保持在最低限度,我想找出存储这些项目的最佳方式。将这些项目拆分成成千上万的哈希值会更好吗?我应该根本不使用哈希吗?有没有办法让它们完全离开堆,这样它们就不会被 GC 检查(如果是这样,我会怎么做)?
没有公共 API 可以控制来自 JavaScript 的垃圾收集。
但这些年来,GC 已经走了很长一段路。现代 GC 实现会注意到一些对象的寿命很长,并将它们放入一个特殊的“区域”,该区域很少被收集。
这究竟是如何工作的完全取决于实现;每个浏览器都做自己的事情,通常,当新的浏览器版本发布时,这也经常发生变化。
编辑内存布局和组织完全无关。如果不花几周时间阅读实际代码,现代 GC 真的很难详细理解。所以我现在解释的是一个非常简化的图;实际代码的工作方式会有所不同(并且一些 GC 会使用完全不同的技巧来实现相同的目标)。
想象一下,GC 对每个对象都有一个计数器,用于计算过去看到它的频率。此外,它还有几个列表,其中保存了不同年龄的对象,即计数器已超过某些阈值的对象。因此,当计数器达到某个限制时,对象将移动到下一个列表。
每次 GC 运行时都会访问第一个列表。第二个列表仅在每 N 次 GC 运行时考虑。
另一种实现可能会将新对象添加到“GC 列表”的顶部,并且对于每次 GC 运行,它只会检查 N 个元素。所以长寿命的对象会在列表中向下移动,一段时间后,它们不会每次都被检查。
这对你来说意味着你不需要做任何事情。GC 会发现你的巨大地图存在很长时间(地图中的所有对象也是如此),一段时间后,它会开始忽略这个数据结构。