如果我需要的内存比 Java 中堆上的内存多,我该怎么办?

What can I do if I require more memory than there is on the heap in Java?

我有一个图形算法,可以生成与不同节点关联的中间结果。目前,我已经通过使用 ConcurrentHashMap<Node, List<Result> 解决了这个问题(我是 运行ning 多线程)。因此,首先我使用 map.get(node).add(result) 添加新结果,然后使用 map.get(node).

一次消耗节点的所有结果

但是,我需要 运行 在一个非常大的图表上,其中中间结果的数量无法放入内存(好旧的 OutOfMemory 异常)。所以我需要一些解决方案来将结果写到磁盘上——因为那里仍然有 space.

看了很多不同的 "off-heap" 地图和缓存以及 MapDB,我认为它们都不适合我。它们似乎都不支持 Multimaps(我想你可以称之为我的地图)或可变值(列表就是这样)。此外,在尝试为每个节点创建新集合时,MapDB 对我来说非常慢(即使使用基于 FST 的自定义序列化程序)。

不过,我很难想象我是第一个也是唯一一个遇到这样问题的人。我所需要的只是一个从键到列表的映射,我只需要将其作为一个整体进行扩展或读取。一个优雅而简单的解决方案会是什么样子?或者是否有任何现有的库可供我使用?

提前感谢您节省了我的一周:)。

编辑
我已经看到很多好的答案,但是,我有两个重要的限制:我不想依赖外部数据库(例如 Redis)并且我不能影响堆大小。

我记得 JVM 运行 的初始最大堆大小很小。如果您使用 -Xmx10000m,您可以告诉 JVM 使用 10,000 MB(或您选择的任何数字)堆 运行。如果您的底层 OS 资源支持更大的堆,那可能会起作用。

  1. 您可以增加堆的大小。堆的大小可以是 配置为大于服务器的物理内存大小,同时 您确保条件正确:

    the size of heap + the size of other applications < the size of physical memory + the size of swap space
    

    比如物理内存为4G,swapspace为4G, 堆大小可以配置为6G。

    但是程序会出现页面交换问题

  2. 您可以使用一些数据库,例如 Redis。 Redis 是键值对 数据库并具有列表结构。

    我认为这是解决您问题的最简单方法。

  3. 您可以压缩 Result 实例。首先,你序列化 实例并压缩它。并定义 class:

    class CompressResult { 
        byte[] result; 
        //... 
    } 
    

    并将Result替换为CompressResult。但是你应该反序列化 当你想使用它时的结果。

    如果 class 结果有很多字段并且非常 复杂.