Latar Belakang
Seperti disebutkan dalam pertanyaan ini , saya menggunakan Scalaz 7 iterasi untuk memproses aliran data yang besar (yaitu, tak terbatas) dalam ruang heap konstan.
Kode saya terlihat seperti ini:
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))
Masalah
Sepertinya saya mengalami kebocoran memori, tetapi saya tidak cukup paham dengan Scalaz / FP untuk mengetahui apakah bug tersebut ada di Scalaz atau di kode saya. Secara intuitif, saya berharap kode ini hanya membutuhkan (dengan urutan) P dikalikan dengan Chunkspasi -size.
Catatan: Saya menemukan pertanyaan serupa yang OutOfMemoryErrorditemui, tetapi kode saya tidak digunakan consume.
Menguji
Saya menjalankan beberapa tes untuk mencoba dan mengisolasi masalahnya. Untuk meringkas, kebocoran hanya muncul muncul ketika kedua zipWithIndexdan groupdigunakan.
// 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
Kode untuk tes:
import scalaz.iteratee._, scalaz.effect.IO, scalaz.std.vector._
// define an enumerator that produces a stream of new, zero-filled arrays
def enumArrs(sz: Int, n: Int) =
Iteratee.enumIterator[Array[Int], IO](
Iterator.continually(Array.fill(sz)(0)).take(n))
// define an iteratee that consumes a stream of arrays
// and computes its length
val i1 = Iteratee.fold[Array[Int], IO, Long](0) {
(c, a) => c + a.length
}
// define an iteratee that consumes a grouped stream of arrays
// and computes its length
val i2 = Iteratee.fold[Vector[Array[Int]], IO, Long](0) {
(c, as) => c + as.map(_.length).sum
}
// define an iteratee that consumes a grouped/zipped stream of arrays
// and computes its length
val i3 = Iteratee.fold[Vector[(Array[Int], Long)], IO, Long](0) {
(c, vs) => c + vs.map(_._1.length).sum
}
// define an iteratee that consumes a zipped stream of arrays
// and computes its length
val i4 = Iteratee.fold[(Array[Int], Long), IO, Long](0) {
(c, v) => c + v._1.length
}
Pertanyaan
- Apakah bug ada di kode saya?
- Bagaimana cara membuat ini berfungsi dalam ruang heap konstan?
-XX:+HeapDumpOnOutOfMemoryErrordan menganalisis dump dengan eclipse MAT eclipse.org/mat untuk melihat baris kode apa yang dipegang pada array.
varpenghitung saat Anda pergi.
Longindeks per potongan akan mengubah algoritme dari ruang heap konstan menjadi non-konstan? Versi non-zip jelas menggunakan ruang heap yang konstan, karena dapat "memproses" sebanyak mungkin potongan yang ingin Anda tunggu.