我遇到了Java堆空间的问题,我在其中尝试对一个数组的连续元素进行分组,以便创建用于计算其转置的矩阵。我在数组中有很多值(26726400),我尝试使用大小为29的桶。但是当我测试下面的代码时,我得到异常java.lang.OutOfMemoryError: Java heap space
val arr = new Array[Int](256 * 3600 * 29)
arr: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
scala> arr.grouped(29).toArray
java.lang.OutOfMemoryError: Java heap space
我的目的是转置矩阵。如果我运行sbt -mem 2048
,这段代码可以正常工作,但这是另一种在不增加堆空间的情况下完成此任务的方法吗?
答案 0 :(得分:1)
这可能不会节省太多内存,但它肯定比grouped
更有效,后者在内部缓冲区之间进行了几次复制。
scala> val arr = new Array[Int](256 * 3600 * 29)
arr: Array[Int] = Array(0, 0, 0,...
scala> Array.tabulate(256 * 3600, 29)((i,j) => arr(i * 29 + j))
res0: Array[Array[Int]] = Array(Array(0, 0, 0,...
我的科学试验明显加快了。
您还可以使用1-dim制表,分配Array.ofDim(29)
和Array.copy
。
答案 1 :(得分:0)
嗯,在具有> 1Gb RAM的机器上的JVM实例的默认内存是RAM / 4。因此,为您的计算机添加更多内存,您不必将该参数传递给sbt。
开玩笑说,这里至少有3份数据副本。首先是原始bricks
实例,然后是arr
操作的结果,然后是grouped
调用的结果。它甚至可能更多,我不确定隐式转换为toArray
,这是调用ArrayOps
方法所必需的(实际上它没有在grouped
类上定义)
根据您的数据大小和类型,一个副本需要大约101Mb的内存,不包括与存储相关的任何开销。要解决此问题,请减少所制作的副本数量。例如,我真的不明白为什么你需要最后一次Array
电话。
作为旁注,如果它不是作业,请考虑使用一些现有的库进行矩阵操作,例如jBLAS。