【问题标题】:How to persist large Java object between invocations of JVM run如何在 JVM 运行调用之间持久化大型 Java 对象
【发布时间】:2018-12-05 20:10:49
【问题描述】:

我正在处理以二进制格式存储在磁盘上的大型图形。从磁盘 (SSD) 读取图表并构建图表大约需要一个小时。一旦构建,图形永远不会改变。该图需要大约 50GB 的内存,这对服务器来说不是问题。然而,我们经常想在图上做很多实验,并且支付每小时的图加载时间会变得很昂贵。我想知道是否有任何方法可以将对象持久保存在内存中,以便 JVM 基本上可以在内存中定位对象。

我知道 JVM 在进程之间共享内存,但我还没有看到任何东西可以让您共享整个对象而不将对象序列化为字节(考虑到昂贵的重建,这可能会很慢)。由于对象庞大(50GB),数据库解决方案似乎也很慢。因为我们没有修改对象(它实际上是静态的),所以我不关心进程之间的并发问题。

我见过的最好的想法是使用FileChannel 将序列化对象映射到内存中,使用始终持久的 JVM,然后让第二个 JVM 从该 FileChannel 读取以反序列化对象。任何其他建议将不胜感激!

【问题讨论】:

  • 为什么需要 2 个 JVM?他们在同一个主机上吗?常规的旧 java 对象序列化(后读取和构造)呢?如果您可以分段访问图表,并且能够在您想做工作时管理偏移量 - 内存映射文件:howtodoinjava.com/java-7/nio/…
  • @MattPavlovich 我希望使用两个 JVM,以便一个可以在内存中持久“托管”大图,然后第二个 JVM 可以根据需要连接以获取对象,而无需支付图构建成本.我可能会多次创建第二个 JVM(在同一张图上进行不同的分析)。此外,是的,两个 JVM 将位于同一主机上。序列化会起作用,但是我仍然需要支付对象构建成本,至少需要 20-30 分钟(这是一个大图)。内存映射文件的想法是我对 FileChannel 对象的建议。 :)
  • 你确定你真的需要一个小时吗?似乎时间很长。也许你可以加快这部分的速度。相当大。
  • @EJP 该图是 10GB 的压缩二进制格式,具有约 1B 的边。 I/O 单独需要 10-15 分钟,然后构建图数据结构需要剩余时间。我宁愿它不需要一个小时,但我们已经对此进行了相当多的优化,并且宁愿将对象保留在内存中以供其他 JVM 使用。
  • 只是保持 JVM 运行并向其发送查询?

标签: java memory-management jvm


【解决方案1】:

我建议使用ChronicleMap(我帮助设计)

它是:

  • 坚持
  • 共享
  • 堆外
  • 可以大于主存
  • 具有将序列化成本降至最低的选项。

例如https://github.com/OpenHFT/Chronicle-Map/blob/master/docs/CM_Tutorial.adoc

interface PostalCodeRange {
    int minCode();
    void minCode(int minCode);

    int maxCode();
    void maxCode(int maxCode);
}

ChronicleMap<Integer, PostalCodeRange> cityPostalCodes = ChronicleMap
    .of(CharSequence.class, PostalCodeRange.class)
    .averageKey("Amsterdam")
    .entries(50_000)
    .createOrRecoverPersistedTo(cityPostalCodesFile, false);

注意:这种情况下的值是堆外内存上的享元,它允许您访问字段而无需反序列化对象。

【讨论】:

  • 我认为这对我们的情况没有帮助,因为我希望图表位于主内存中(不需要堆外),并且程序最终将访问图表中的所有内容,通常是多次,所以不需要轻量级设计。我们研究了与 Redis 类似的东西,但 TCP/IP 开销太大。
  • @DavidJurgens 将 TCP 和序列化带入堆成本,当可以存储在内存映射文件中时,您将获得堆外数据结构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多