Scala fo/ yield中的内存泄漏



使用下面的稀疏矩阵乘法例程遇到内存问题。

对于非常大的稀疏矩阵工作得很好,但随着矩阵密度的增加,它会停止工作。

看起来像是内存泄漏。

kk & lt; - (A.colPtrs (jj) (A.colPtrs (jj + 1) 1))//失败在这里

def sparseMatrixMultiply(A:CSCMatrix[Double], B:CSCMatrix[Double]) = {
val n = B.cols
val Bvals = B.activeValuesIterator.toArray
val Avals = A.activeValuesIterator.toArray
val entries =
for {
j <- (0 to (n-1))/*.par*/
k <- (B.colPtrs(j) to (B.colPtrs(j + 1)-1))
jj = B.rowIndices(k) 
kk <- (A.colPtrs(jj) to (A.colPtrs(jj + 1)-1)) //  get stuck here 
i = A.rowIndices(kk) 
} yield {
println(s"$j $k $jj $kk $i ${Bvals(k)} ${Avals(kk)}")
(i, j, Bvals(k) * Avals(kk))
}
}
val coo = SparseMatrix.fromCOO(A.rows,B.cols, entries/*.seq*/)
//converting back to breeze CSCMatrix
new breeze.linalg.CSCMatrix[Double](coo.values, coo.numRows, coo.numCols, coo.colPtrs, coo.rowIndices)
}

我试过把它分成单独的块,但是迭代很快就会在同一步骤耗尽内存

kk & lt; - (A.colPtrs (jj) (A.colPtrs (jj + 1) 1))

它只是分配内存太快的GC ?或者在for/yield完成之前保留所有范围实例

查看GC如何管理for/yield理解中的内存

感谢

for推导式是用于嵌套映射和平面映射的语法。你所做的是:

for {
j <- (0 to (n-1))/*.par*/
k <- (B.colPtrs(j) to (B.colPtrs(j + 1)-1))
jj = B.rowIndices(k) 
kk <- (A.colPtrs(jj) to (A.colPtrs(jj + 1)-1)) //  get stuck here 
i = A.rowIndices(kk) 
} yield {
println(s"$j $k $jj $kk $i ${Bvals(k)} ${Avals(kk)}")
(i, j, Bvals(k) * Avals(kk))
}

(0 to (n-1)).flatMap { j =>
(B.colPtrs(j) to (B.colPtrs(j + 1)-1)).flatMap { k =>
val jj = B.rowIndices(k)
(A.colPtrs(jj) to (A.colPtrs(jj + 1)-1)).map { kk =>
val i = A.rowIndices(kk)
println(s"$j $k $jj $kk $i ${Bvals(k)} ${Avals(kk)}")
(i, j, Bvals(k) * Avals(kk))
}
}
}

每个嵌套是一个闭包,

  • 存储创建时存在的外部嵌套中的所有变量(因此在代码中出现在它上面的所有内容)
  • 必须计算整个子结果
  • 只能在返回子结果并将其合并到外部上下文
  • 中存在的更大结果的内部构建器之后才能被整个垃圾收集。

例如,如果每个嵌套平均引入10个元素,则通过中间步骤创建10 x 10 x 10个元素的乘积(10个元素,每个元素都有一个闭包,该闭包创建10个元素,每个闭包创建最终结果,最内层必须被平化,然后中间嵌套必须被平化,最外层的结果必须被平化)。虽然你的问题表明中间对象的数量远远超过1000个数量级。

这是很多中间结果,这不是内存泄漏。这就是它的工作原理。所有的内存都会在您退出理解后被收集。范围本身很轻,但是当您使用.map.flatMap时,您将它们转换为IndexedSeq,这很可能是一些急于记忆的数据结构,它将立即计算最终结果,而不允许JVM忘记任何东西(由于接口只保证IndexedSeq,因此很难假设是哪一个,可能是ListVector,但您无法保证)。

您可以尝试将每个Range转换为LazyList(2.13)或Stream(2.12及之前),然后在传入fromCOO之前将此惰性数据结构转换为IteratorIterable。这种理解方式将构建一个结构,该结构只分配和记忆计算下一个元素所需的量,并立即忘记不再需要的所有内容。比如:

val entries = for {
j <- (0 to (n-1)).to(LazyList)
k <- (B.colPtrs(j) to (B.colPtrs(j + 1)-1)).to(LazyList)
jj = B.rowIndices(k) 
kk <- (A.colPtrs(jj) to (A.colPtrs(jj + 1)-1)).to(LazyList)
i = A.rowIndices(kk) 
} yield {
println(s"$j $k $jj $kk $i ${Bvals(k)} ${Avals(kk)}")
(i, j, Bvals(k) * Avals(kk))
}
SparseMatrix.fromCOO(A.rows,B.cols, entries.toIterable)

相关内容

  • 没有找到相关文章

最新更新