最大化Java堆空间
我试图在Java中使用非常大的矩形矩阵,大小为n = 1e6或更多。 矩阵并不稀疏,所以我没有看到将它们表示为二维数组,它需要n ^ 2 * sizeof(int)位内存。 显然,即使在我的机器允许的情况下添加编译器标志以像堆一样使用时,我也会遇到堆溢出错误。
为了这个问题,我愿意假设我有完美的计算机(无限RAM等),尽管实际上我是在一台拥有16个RAM的64位机器上。 看起来我的机器是如此相关,因为我受JVM的限制,而不是我的实际硬件(因为JVM不能拥有比我的物理机器更多的内存)。
我理解(并且被引用,例如,在这里创建一个非常大的Java数组),即使在理论上,Java数组也不能像用于索引的那样大于MAX_INT。
我的问题是:是否有任何方法可以将额外内存从JVM堆中取出
我明白,如果有的话,他们可能不会给我更多的信息。
例如
在C中,我可以声明静态常量变量,并将它们移动到代码的数据部分,该部分将比堆空间大得多,并且比堆栈多得多(静态变量存储在哪里(在C / C ++中)?) 。
在Java中,即使我将变量复制到“数据”部分,该值也会进入java中的主堆静态分配 - 堆,堆栈和永久生成,这意味着我已经成功移动了一个完整的字节堆(耶!)
我的解决方案
我的“解决方案”并不是真正的解决方案。 我做了一个简单的数据结构,它使用RandomFileAccess io过程将读取和写入的数组访问替换为外部文件。 它仍然是不变的时间访问,但是我们从Java的一个最快的操作转到非常慢的过程(尽管我们可以一次从文件中提取“缓存”行,这使得该过程非常快速)。 更好的想法?
不是我的问题
我不问如何在java的最大数组大小之上创建一个数组。 这是不可能的。 这些是嵌套数组 - 单个n大小的数组很好,其中n个会导致问题。
我不问这个如何处理“java.lang.OutOfMemoryError:Java堆空间”错误(64MB堆大小)。 垃圾收集不相关 - 我甚至无法让数组放在一起,不用担心它何时被删除。
我也不能使用迭代器(我认为),否则这是一种可能性; 矩阵乘法等功能需要能够直接进行索引
注意:Java不适合在非常大的矩阵上进行操作。 我最好用算盘。 但是我在这里,那超出了我的控制范围。
你原来的问题有一些缺失的方面; 例如,我不相信你必须使用这样的大矩阵,并在运行之间“忘记它们”。 好吧,也许你会,我不知道。
无论如何:你的RandomAccessFile
的使用是,imho,差不多; 只有如果我是你,我会使用FileChannel.map()
。 在Unix系统上,它基本上是调用mmap(2)
一种方法。 在下面的场景中,我假设你有一个FileChannel
到你的矩阵(我认为你理解我的意思)。
由于您使用矩阵,因为它看起来像矩阵中任何给定“坐标”处的值都具有相同的长度,这意味着您可以轻松地计算文件中的偏移量以读取和/或将给定值写入矩阵。 当然,你不想映射该值,而是包含该值的窗口; 使窗口足够大以便有用,并且不用担心堆空间消耗: FileChannel.map()
不消耗堆空间 (除了对象簿记)。 在64位JVM上,您不必担心; 如果您使用的是32位JVM,则必须考虑地址空间耗尽。
当然,还有过期问题:您需要多长时间才能保持活动状态? 这完全取决于你的程序以及你如何处理它。 但是使用FileChannel
并映射相关区域是一种方法。 但是,应该提醒您,映射超过2 ^ 31 - 1个字节是不安全的; 例如,解决2 ^ 30(1 GiB)字节的窗口; 并提醒你可以将ByteBuffer
转换成IntBuffer
。
编辑:一些相关的链接:
FileChannel.open()
; FileChannel.map()
; ByteBuffer
及其asIntBuffer()
方法; IntBuffer
。 上一篇: Maximizing Java Heap Space
下一篇: Is it possible to destroy static variables programmatically?