Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Scalaz 7 zipWithIndex/group枚举避免内存泄漏_Scala_Scalaz_Iterate - Fatal编程技术网

使用Scalaz 7 zipWithIndex/group枚举避免内存泄漏

使用Scalaz 7 zipWithIndex/group枚举避免内存泄漏,scala,scalaz,iterate,Scala,Scalaz,Iterate,背景 如中所述,我正在使用Scalaz 7迭代者在恒定堆空间中处理一个大的(即无界的)数据流 我的代码如下所示: type ErrorOrT[M[+_], A] = EitherT[M, Throwable, A] type ErrorOr[A] = ErrorOrT[IO, A] def processChunk(c: Chunk, idx: Long): Result def process(data: EnumeratorT[Chunk, ErrorOr]): IterateeT[Ve

背景

如中所述,我正在使用Scalaz 7迭代者在恒定堆空间中处理一个大的(即无界的)数据流

我的代码如下所示:

type ErrorOrT[M[+_], A] = EitherT[M, Throwable, A]
type ErrorOr[A] = ErrorOrT[IO, A]

def processChunk(c: Chunk, idx: Long): Result

def process(data: EnumeratorT[Chunk, ErrorOr]): IterateeT[Vector[(Chunk, Long)], ErrorOr, Vector[Result]] =
  Iteratee.fold[Vector[(Chunk, Long)], ErrorOr, Vector[Result]](Nil) { (rs, vs) =>
    rs ++ vs map { 
      case (c, i) => processChunk(c, i) 
    }
  } &= (data.zipWithIndex mapE Iteratee.group(P))
问题

我似乎遇到了内存泄漏,但我对Scalaz/FP不够熟悉,不知道该错误是在Scalaz中还是在我的代码中。直观地说,我希望这段代码只需要P乘以
块大小的空间

注意:我发现其中遇到了
outofmemory错误
,但我的代码没有使用
consume

测试

我运行了一些测试,试图找出问题。总而言之,只有在同时使用
zipWithIndex
group
时,泄漏才会出现

// no zipping/grouping
scala> (i1 &= enumArrs(1 << 25, 128)).run.unsafePerformIO
res47: Long = 4294967296

// grouping only
scala> (i2 &= (enumArrs(1 << 25, 128) mapE Iteratee.group(4))).run.unsafePerformIO
res49: Long = 4294967296

// zipping and grouping
scala> (i3 &= (enumArrs(1 << 25, 128).zipWithIndex mapE Iteratee.group(4))).run.unsafePerformIO
java.lang.OutOfMemoryError: Java heap space

// zipping only
scala> (i4 &= (enumArrs(1 << 25, 128).zipWithIndex)).run.unsafePerformIO
res51: Long = 4294967296

// no zipping/grouping, larger arrays
scala> (i1 &= enumArrs(1 << 27, 128)).run.unsafePerformIO
res53: Long = 17179869184

// zipping only, larger arrays
scala> (i4 &= (enumArrs(1 << 27, 128).zipWithIndex)).run.unsafePerformIO
res54: Long = 17179869184
问题

  • 我的代码中有bug吗
  • 如何在恒定的堆空间中工作

对于那些使用较旧的
iteratee
API的人来说,这算不上什么安慰,但我最近验证了一个与之相当的测试通过了。这是一个较新的流处理API,旨在取代
iteratee

为完整起见,以下是测试代码:

// create a stream containing `n` arrays with `sz` Ints in each one
def streamArrs(sz: Int, n: Int): Process[Task, Array[Int]] =
  (Process emit Array.fill(sz)(0)).repeat take n

(streamArrs(1 << 25, 1 << 14).zipWithIndex 
      pipe process1.chunk(4) 
      pipe process1.fold(0L) {
    (c, vs) => c + vs.map(_._1.length.toLong).sum
  }).runLast.run
//创建一个包含`n`数组的流,每个数组中都有`sz`int
def streamArrs(sz:Int,n:Int):进程[任务,数组[Int]]=
(进程emit Array.fill(sz)(0))。重复take n

(streamArrs)(1)我最后将此报告为。这不会有任何乐趣,但您可以尝试
-XX:+HeapDumpOnOutOfMemoryError
并使用eclipse MAT分析转储,以查看哪些代码行保留在数组上。@huynhjl FWIW,我尝试使用JProfiler和MAT分析堆,但完全无法遍历对anon的所有引用Imous函数类等。Scala真的需要专门的工具来完成这类工作。如果没有泄漏,只是因为您正在做的事情需要大量的内存,怎么办?您可以轻松地复制zipWithIndex,而不需要特定的FP构造,只需在运行时维护一个
var
计数器。@EzekielVictor我不确定我是否理解这个评论。你的意思是,在每个块中添加一个
Long
索引会将算法从常量堆空间更改为非常量堆空间?非压缩版本显然使用常量堆空间,因为它可以“处理”你愿意等待的任意多个块。
// create a stream containing `n` arrays with `sz` Ints in each one
def streamArrs(sz: Int, n: Int): Process[Task, Array[Int]] =
  (Process emit Array.fill(sz)(0)).repeat take n

(streamArrs(1 << 25, 1 << 14).zipWithIndex 
      pipe process1.chunk(4) 
      pipe process1.fold(0L) {
    (c, vs) => c + vs.map(_._1.length.toLong).sum
  }).runLast.run