0

不久前,我问了这个关于 ChronicleMap 被用作Map<String,Set<Integer>>. 基本上,我们有一个集合,其平均值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. 有一个“最大集合大小”并将非常大的集合分成许多较小的集合,相应地设置密钥。例如,如果我的密钥XYZ产生Set<Integer>大小为 10000 的密钥,也许我可以将其拆分为 5 个密钥XYZ:1XYZ:2等,每个密钥的大小为 2000。这感觉就像我可以在 ChronicleMap 中配置的东西一样,并且导致很多代码感觉它不应该是必要的。我在另一个问题中也提到了同样的计划。

其他想法/想法表示赞赏!

4

1 回答 1

1

如果您不maxChunksPerEntry()手动指定,则条目的最大大小受段层大小的限制,以块为单位。因此,您需要使段层大小更大。actualSegments(1)如果您不打算从 JVM 中的多个线程同时访问映射,您可以尝试做的第一件事是配置。ChronicleMapBuilder.actualChunkSize()您可以通过和对这些配置actualChunksPerSegmentTier()进行额外控制entriesPerSegment()

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

同样对于如此大的值,我建议开发和使用内存效率更高的值序列化程序,因为默认值会产生大量垃圾。例如。它可以使用从 fastutil 或 Koloboke 或 Koloboke 编译库IntSet实现的原语。Set<Integer>

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

于 2016-12-14T20:21:45.997 回答