前段时间,我问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个块的巨大值。
所以我的问题是:解决这个问题的最佳方法是什么?我正在考虑的一些方法,但仍然不确定:
ChronicleMapBuilder.maxChunksPerEntry
或ChronicleMapBuilder.actualChunkSize
。那就是说,我如何确定地找出应该设置的内容?此外,如果它设置得太高,这可能会导致大量碎片和性能降低,对吗?XYZ
,其大小为Set<Integer>
,那么我可以将其分为5个密钥XYZ:1
,XYZ:2
等,每个密钥都有一组2000年的大小,这就像我在ChronicleMap中可以配置的东西,并且导致很多代码感觉它不应该是必要的。我也有同样的计划在我的另一个问题中提到。赞赏其他想法/想法!
答案 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已经过时了。