【发布时间】:2021-03-01 18:02:07
【问题描述】:
我是 JVM 中堆外存储的新手,ChronicleMap 看起来很适合堆外存储。但我主要关心的是性能。
我确实使用配置运行了简单的测试
ChronicleMapBuilder<IntValue, BondVOImpl> builder =
ChronicleMapBuilder.of(IntValue.class, BondVOImpl.class)
.minSegments(512)
.averageValue(new BondVOImpl())
.maxBloatFactor(4.0)
.valueMarshaller(new BytesMarshallableReaderWriter<>(BondVOImpl.class))
.entries(ITERATIONS);
发现以下结果
----- Concurrent HASHMAP ------------------------
Time for putting 7258
Time for getting 678
----- CHRONICLE MAP ------------------------
Time for putting 4704
Time for getting 2246
与 Concurrent HashMap 相比,读取性能相当低。
我已经尝试使用 1024/2048 段,默认膨胀因子,默认 Marshaller。但结果还是一样。
我只是想利用堆外特性来减少 GC 暂停,并且无意使用持久性事物或复制或使用 JVM 之外的映射。
所以问题是我应该使用 ChronicleMap 还是坚持使用 ConcurrentHashMap? 或者在 ChronicleMap 的情况下,我可以使用任何其他配置来提高性能?
提前致谢。
** 使用https://github.com/OpenHFT/Chronicle-Map/blob/master/src/test/java/net/openhft/chronicle/map/perf/MapJLBHTest.java 进行基准测试:**
【问题讨论】:
-
您不能在不编组对象的情况下使用堆外存储。当然,这比仅仅存储一个引用更昂贵。只有您可以回答这个重要问题,这种方法是否真正“减少了您的设置中的 GC 暂停”?多少钱?将收益与成本进行比较,然后再决定……
-
@Holger 我建议你回答你的评论,这样他的问题就可以被标记为已解决。
-
1) 你是如何测试得到这些数字的——没有代码和证明,它们是无关紧要的。 2)堆外不一定是关于较低的暂停时间。如果你真的想要更短的暂停时间,你应该先采取一些小步骤,比如用你的 current 收集器分析 GC 日志(可能会改进),然后很可能转移到
Shenandoah或ZGC。事实上,我们前段时间在我们的代码库中使用了堆外,并在我们迁移到Shenandoah时将其完全删除。 -
这不是一个有用的比较。
ConcurrentHashMap,顾名思义,专为并发更新而设计。当您要填写一次地图,然后只进行读取访问时,普通的HashMap就足够了。对于现实生活中的案例,您必须使用不同的参数执行多个测试,例如不同的数据量,不同的并发性,不断变化的读写模式,然后,看看地图如何响应这些变化的参数。并且具有较大的 GC 暂停时间并不能证明ChronicleMap会改善这种情况。只有实际测试才能判断。 -
你没有抓住重点。
ConcurrentHashMap擅长处理并发写入,而您没有检查ChronicleMap的执行情况。也许,单线程一次性填充是唯一一个ChronicleMap似乎更快的操作,而且也只有在执行不充分的基准测试时。你确定你考虑过How do I write a correct micro-benchmark in Java?中讨论的每一点吗?我怀疑它,因为那时你已经检查了环境参数的影响。
标签: java garbage-collection jvm chronicle-map off-heap