填充ChronicleMap时,IllegalArgumentException具有值大小的高可变性

时间:2016-12-13 20:22:33

标签: java chronicle chronicle-map

前段时间,我问this question有关用作Map<String,Set<Integer>>的ChronicleMap的问题。基本上,我们有一个集合,平均Set<Integer>可能是400,但最大长度是20,000。使用ChronicleMap 2,这导致了相当恶性的JVM崩溃。我转到ChronicleMap 3.9.1并且现在开始出现异常(至少它不是JVM崩溃):

java.lang.IllegalArgumentException: Entry is too large: requires 23045 chucks, 6328 is maximum.
    at net.openhft.chronicle.map.impl.CompiledMapQueryContext.allocReturnCode(CompiledMapQueryContext.java:1760)
    at net.openhft.chronicle.map.impl.CompiledMapQueryContext.allocReturnCodeGuarded(CompiledMapQueryContext.java:120)
    at net.openhft.chronicle.map.impl.CompiledMapQueryContext.alloc(CompiledMapQueryContext.java:3006)
    at net.openhft.chronicle.map.impl.CompiledMapQueryContext.initEntryAndKey(CompiledMapQueryContext.java:3436)
    at net.openhft.chronicle.map.impl.CompiledMapQueryContext.putEntry(CompiledMapQueryContext.java:3891)
    at net.openhft.chronicle.map.impl.CompiledMapQueryContext.doInsert(CompiledMapQueryContext.java:4080)
    at net.openhft.chronicle.map.MapEntryOperations.insert(MapEntryOperations.java:156)
    at net.openhft.chronicle.map.impl.CompiledMapQueryContext.insert(CompiledMapQueryContext.java:4051)
    at net.openhft.chronicle.map.MapMethods.put(MapMethods.java:88)
    at net.openhft.chronicle.map.VanillaChronicleMap.put(VanillaChronicleMap.java:552)

我怀疑这仍然是因为我的价值远远高于平均值。我假设ChronicleMap根据我给构建器的平均值确定了块的最大数量为6328,但是并不期望有一个需要23045个块的巨大值。

所以我的问题是:解决这个问题的最佳方法是什么?我正在考虑的一些方法,但仍然不确定:

  1. 使用ChronicleMapBuilder.maxChunksPerEntryChronicleMapBuilder.actualChunkSize。那就是说,我如何确定地找出应该设置的内容?此外,如果它设置得太高,这可能会导致大量碎片和性能降低,对吗?
  2. 拥有&#34;最大收集尺寸&#34;并将非常大的集合拆分成许多较小的集合,相应地设置密钥。例如,如果我的密钥为XYZ,其大小为Set<Integer>,那么我可以将其分为5个密钥XYZ:1XYZ:2等,每个密钥都有一组2000年的大小,这就像我在ChronicleMap中可以配置的东西,并且导致很多代码感觉它不应该是必要的。我也有同样的计划在我的另一个问题中提到。
  3. 赞赏其他想法/想法!

1 个答案:

答案 0 :(得分:1)

如果您未手动指定maxChunksPerEntry(),则条目的最大大小限制为段层大小。所以你需要的是使分段层大小更大。如果您不打算同时从JVM中的多个线程访问映射,那么您可以尝试执行的第一件事是配置actualSegments(1)。您可以通过ChronicleMapBuilder.actualChunkSize()actualChunksPerSegmentTier()entriesPerSegment()对这些配置进行其他控制。

默认情况下,ChronicleMapBuilder选择块大小在配置的平均值大小的1/8和1/4之间。因此,如果您的段层大小为6328块,则您的段配置为包含大约1000个条目。如果您的平均值设置大小为400个元素且最大值为20,000,则平均值和最大值之间的差异应为大约50倍,但从堆栈跟踪看起来您的其中一个条目远远大于平均值的2000倍。可能你没有考虑到什么。

同样对于如此大的值我建议开发并使用更多内存有效的值序列化器,因为默认值会产生大量垃圾。 E. g。它可以使用原始IntSet来实现来自fastutil或Koloboke或Koloboke Compile库的Set<Integer>

我建议现在使用最新版本,Chronicle Map 3.9.1已经过时了。