Lý lịch
Như đã lưu ý trong câu hỏi này , tôi đang sử dụng các lần lặp Scalaz 7 để xử lý một luồng dữ liệu lớn (tức là không bị ràng buộc) trong không gian đống không đổi.
Mã của tôi trông như thế này:
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))
Vấn đề
Có vẻ như tôi đã gặp phải tình trạng rò rỉ bộ nhớ, nhưng tôi không đủ quen thuộc với Scalaz / FP để biết liệu lỗi nằm trong Scalaz hay trong mã của tôi. Theo trực giác, tôi mong đợi mã này chỉ yêu cầu (theo thứ tự) P nhân với Chunk
không gian -size.
Lưu ý: Tôi đã tìm thấy một câu hỏi tương tự mà trong đó câu hỏi này OutOfMemoryError
đã gặp phải, nhưng mã của tôi không sử dụng consume
.
Thử nghiệm
Tôi đã chạy một số thử nghiệm để thử và cô lập vấn đề. Tóm lại, rò rỉ chỉ xuất hiện khi cả hai zipWithIndex
và group
được sử dụng.
// 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
Mã cho các bài kiểm tra:
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
}
Câu hỏi
- Có phải lỗi trong mã của tôi không?
- Làm thế nào tôi có thể làm cho điều này hoạt động trong không gian đống không đổi?
-XX:+HeapDumpOnOutOfMemoryError
và phân tích kết xuất với eclipse MAT eclipse.org/mat để xem dòng mã nào đang giữ các mảng.
var
đếm khi bạn thực hiện.
Long
chỉ mục duy nhất cho mỗi đoạn sẽ thay đổi thuật toán từ không gian heap không đổi thành không đổi? Phiên bản không nén rõ ràng sử dụng không gian đống không đổi, vì nó có thể "xử lý" bao nhiêu phần mà bạn sẵn sàng chờ đợi.