【问题标题】:Maximizing Java Heap Space最大化 Java 堆空间
【发布时间】:2015-01-01 06:19:37
【问题描述】:

我正在尝试在 Java 中使用非常大的方阵,大约为 n = 1e6 或更多。矩阵不是稀疏的,所以我看不到将它们表示为二维数组的方法,这需要 n^2 * sizeof(int) 位内存。显然,我遇到了堆溢出错误,即使添加编译器标志以使用我的机器允许的最大堆也是如此。

为了这个问题,我愿意假设我拥有完美的计算机(无限 RAM 等),但实际上我使用的是具有 16 GB RAM 的 64 位计算机。似乎我的机器只是如此相关,因为我受到 JVM 而不是我的实际硬件的限制(因为 JVM 不能比我的物理机器拥有 更多 内存)。

我理解(并且被引用,例如,这里 Making a very large Java array)Java 数组不能,即使在理论上,也不能大于用于索引的 MAX_INT。

我的问题是:有没有办法从 JVM 堆中哄出额外的内存

我知道,如果有的话,他们可能不会为我提供更多信息。

举例

在 C 语言中,我可以声明静态常量变量并将它们移动到代码的数据部分,这将具有比堆和堆栈更多的空间 (Where are static variables stored (in C/C++)?)。

在 Java 中,即使我将变量复制到“数据”部分,该值也会进入主堆 static allocation in java - heap, stack and permanent generation 这意味着我已经成功地将一个完整字节从堆中移出(耶!)

我的解决方案

我的“解决方案”并不是真正的解决方案。我制作了一个简单的数据结构,它使用 RandomFileAccess io 过程将数组访问替换为对外部文件的读写。它仍然是恒定时间访问,但是我们从 Java 最快的操作之一变成了一个非常非常慢的过程(尽管我们可以一次从文件中提取“缓存”行,这使得该过程非常快)。 更好的想法?

不是我的问题

我不是在问如何使数组超过 java 的最大数组大小。这是不可能的。这些是嵌套数组 - 单个 n 大小的数组很好,其中 n 个会导致问题。

我不是在问这个 How to deal with "java.lang.OutOfMemoryError: Java heap space" error (64MB heap size) 。垃圾收集无关紧要 - 我什至无法制作数组,更不用说担心它何时被删除。

我也不能使用迭代器(我认为),否则这是可能的;像矩阵乘法这样的函数需要能够直接索引

注意:Java 不是对非常大的矩阵进行运算的正确语言。我最好用算盘。但我在这里,这是我无法控制的。

【问题讨论】:

  • 能否将计算分布在多个 JVM 中?使用类似 JPPF,here 就是一个例子
  • 在运行时分配更多内存行得通吗?
  • 你可以.allocateDirect() 一些ByteBuffers,并使用包装类
  • “我们从 Java 最快的操作之一变成了一个非常非常慢的过程” FileChannel.map();然而,与你不同的是,我必须处理chars,而不是bytes,所以我的用例比你的更复杂。也许你可以看看我所做的并从中构建:github.com/fge/largetext
  • @shekhar 谢谢,从长远来看,这似乎是最强大的选择

标签: java memory-management


【解决方案1】:

您的原始问题缺少一些方面;例如,我无法相信您必须使用如此大的矩阵,而只是在运行之间“忘记它们”。好吧,也许你知道,我不知道。

无论如何:你对RandomAccessFile 的使用,恕我直言,差不多了;只是如果我是你,我会使用FileChannel.map()。在 Unix 系统上,它基本上是一种调用 mmap(2) 的方法。在下面的场景中,我假设您的矩阵有一个FileChannel(我认为您明白我的意思)。

由于您使用矩阵,因为看起来矩阵中任何给定“坐标”处的值都具有相同的长度,这意味着您可以轻松计算文件的偏移量以读取和/或写入给定值进入矩阵。当然,您不会想要映射 that 值,而是映射包含该值的窗口;使窗口足够大以便有用,并且不要担心堆空间消耗:FileChannel.map() 不消耗堆空间(保存对象簿记)。在 64 位 JVM 上,您不必担心;如果您使用的是 32 位 JVM,则必须考虑地址空间耗尽。

当然,还有到期问题:您需要这个或那个映射多长时间才能保持活动状态。这完全取决于你的程序以及你用它做什么。但是使用FileChannel 并映射相关区域是可行的方法。但是,应该提醒您,映射超过 2^31 - 1 个字节是不安全的;例如,满足 2^30 (1 GiB) 字节窗口;并提醒您可以将ByteBuffers 转换为IntBuffers。


编辑:一些相关链接:

【讨论】:

    猜你喜欢
    • 2010-11-06
    • 2013-01-03
    • 2021-09-09
    • 2011-01-25
    • 2014-08-10
    • 2012-08-07
    • 2013-07-21
    • 1970-01-01
    • 2018-03-31
    相关资源
    最近更新 更多