当值的大小变化很大时,ChronicleMap 会导致 JVM 崩溃

ChronicleMap causes JVM to crash when values are highly variable in size

到目前为止,我们已经成功地使用 ChronicleMap 完成了我们想要使用它的大多数事情,并且大多数数据集都运行良好。我们的一个用例是将其用作多图,涵盖了这样做的大部分问题。在这种情况下,我们专门将其用作 Map<String,Set<Integer>>。但是,我们 运行 遇到了一些有趣的 JVM 崩溃,并且在找到确定性模式以便我们避免它们时遇到困难。

因此,在我们将所有 Set<Integer> 放入 ChronicleMap 之前,我们将其完全放在 JVM 中,因此我们立即写入以减少碎片。由于我们将它完全存储在内存中,因此我们可以确定最大和平均 Set<Integer> 的大小,并且可以使用 ChronicleMapBuilder.averageValueSize 轻松地适当调整 ChronicleMap 的大小。在大多数情况下,这工作得很好。

然而,在某些情况下,当 Set<Integer> 的大小偏离平均值太远时,JVM 会崩溃。例如,平均大小可能是 400,但我们可以有包含 20,000 个整数的离群值集。我们仍然可以使用一组 400 个整数的平均序列化大小来调整地图的大小,它开始填充 ChronicleMap 直到它到达一个非常大的列表。

所以问题是:我如何计算出我可以偏离平均值多少?我希望平均值确实是平均值,但似乎有一些最大值会导致 JVM 死机。

我们设计了一种算法将大集合拆分成小集合(例如,如果密钥是 AAA,那么现在有密钥 AAA:1、AAA:2、... AAA:n ).拆分集的大小是平均大小的 10 倍。换句话说,如果平均大小为 500,但我们有一个 20,000 的集合,我们会将其分成四个 5,000 (500 * 10) 个元素集。

这在大多数情况下都有效,但随后我们 运行 进入另一个奇怪的案例,甚至这种拆分还不够。我将系数减小到平均大小的 5 倍,现在它又可以工作了……但我怎么知道它足够小?我认为了解源问题或如何准确确定是什么原因是最好的方法,但唉,我不知道为什么 ChronicleMap 在这里挣扎。

此外,FWIW,我使用的是旧版本 2.1.17。如果这是一个在较新版本中修复的错误,我想知道有关该错误的一些细节,以及我们是否可以通过我们自己的方式避免它(例如拆分集合)但仍然继续使用 2.1.17(我们稍后会升级;只是不想再搅局了。

如果不重现错误,我不能 100% 确定,但我知道为什么在这种情况下会发生 JVM 崩溃。如果我是对的,如果您的条目大小超过 ChronicleMap 的 64 * chunkSize,就会发生这种情况。 chunk size 可以直接配置,但是如果你只配置 average key 和 value sizes,它默认为 2 的幂,即介于 averageEntrySize/8 和 averageEntrySize/4 之间,其中平均条目大小是您的 averageKeySize 和 averageValueSize,加上一些内部开销。所以在你的情况下,如果你有平均值 - 400 或 500 组整数(每个 4 字节),+ 小键,我想 chunkSize 计算为 256 字节,所以你的条目应该小于 256 * 64 = 16384 字节。

同样,如果我对这个错误的来源的假设是正确的,那么 Chronicle Map 3 不应该有这个错误并且应该允许任意大于平均大小或块大小的条目。