当值的大小高度可变时,ChronicleMap会导致JVM崩溃



到目前为止,我们已经成功地将ChronicleMap用于我们想要使用它的大多数事情,并且大多数数据集都运行良好。我们的一个用例是将它用作多映射,涵盖了这样做的大部分问题。我们将它用作Map<String,Set<Integer>>,特别是在本例中。然而,我们遇到了一些有趣的JVM崩溃,并且很难找到确定性模式来避免它们。

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

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

所以问题是:我如何计算出我与平均值的偏差有多大?我希望平均值确实是一个平均值,但似乎有一个最大值超过了这个值,导致JVM死亡。

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

这在大多数情况下都有效,但后来我们遇到了另一个奇怪的情况,即使是这种分裂也不够。我把系数降到了平均尺寸的5倍,现在它又起作用了。。。但我怎么知道它足够小?我认为了解来源问题或如何确定确切的原因是最好的方法,但遗憾的是,我不知道ChronicleMap为什么在这里挣扎。

此外,FWIW,我使用的是旧版本2.1.17。如果这是一个在新版本中修复的错误,我想知道关于这个错误的一些细节,以及我们是否可以通过自己的方式避免它(比如拆分布景),但仍然使用2.1.17(我们稍后会升级;只是不想再捣乱太多)。

如果不重现错误,我不能100%确定,但我知道为什么在这种情况下会发生JVM崩溃。如果我是对的,如果您的条目大小超过ChronicleMap的64*chunkSize,就会发生这种情况。区块大小可以直接配置,但如果只配置平均键和值大小,则默认为2的幂,即介于averageEntrySize/8和averageEntrySize/4之间,其中平均条目大小是您的averageKeySize和averageValueSize的总和,加上一些添加的内部开销。因此,在您的情况下,如果您有平均值-400或500 int(每个4字节)的集合,+小密钥,我假设chunkSize计算为256字节,因此您的条目应该小于256*64=16384字节。

同样,如果我从这个bug的来源来看是正确的,Chronicle Map 3不应该有这个bug,并且应该允许任意大于平均大小或块大小的条目。

最新更新