-
Notifications
You must be signed in to change notification settings - Fork 604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Moving data through queue leaks memory #1026
Comments
I'm running it from sbt via Here is a full program for copy-pasting
package com.example
import cats.effect.IO
import fs2._
import fs2.StreamApp.ExitCode
import cats.syntax.apply._
object MemorySanityCheck extends StreamApp[IO] {
import scala.concurrent.ExecutionContext.Implicits._
override final def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, ExitCode] =
(io
.readInputStream[IO](IO(System.in), 32, false)
.takeWhile(_ != '\n') //read System.in to the end
.drain
.onFinalize(IO(println("Exiting...")) *> requestShutdown) mergeHaltBoth app(
args,
requestShutdown).evalMap(_ => IO.unit).drain).handleErrorWith(err =>
Stream.eval(IO {
err.printStackTrace(System.out)
ExitCode.Error
}))
def app(args: List[String], requestShutdown: IO[Unit]): Stream[IO, Any] =
Stream.eval(async.boundedQueue[IO, Either[Throwable, Option[Int]]](10)).flatMap { queue =>
queue.dequeueAvailable.rethrow.unNoneTerminate
.concurrently(
Stream.constant(1, 128).covary[IO].noneTerminate.attempt.evalMap(queue.enqueue1(_)))
.evalMap(_ => IO.unit)
}
} |
Promise, created at this line gets filled with unset callbacks |
@avakhrenev I'm surprised it's the promise in |
That's what I've seen after instrumenting |
@SystemFw Totally guessing here, but this could occur if the cancellation action in |
|
It may be triggered by surrounding code, which reads from input stream simultaneously with running data through queue using |
ah, However, the minimal snippet does not have that. |
@avakhrenev I just ran the sample code without the surrounding stream interruption stuff and I haven't been able to reproduce a memory leak. I suspect the real leak is in merge when one of the sides doesn't make progress. |
a leak on |
Interesting, I've just removed reading from input stream with package com.example
import cats.effect.IO
import fs2._
import fs2.StreamApp.ExitCode
object MemorySanityCheck extends StreamApp[IO] {
import scala.concurrent.ExecutionContext.Implicits._
override final def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, ExitCode] = {
Stream.eval(async.boundedQueue[IO, Either[Throwable, Option[Int]]](10)).flatMap { queue =>
queue.dequeueAvailable.rethrow.unNoneTerminate
.concurrently(
Stream.constant(1, 128).covary[IO].noneTerminate.attempt.evalMap(queue.enqueue1(_)))
.evalMap(_ => IO.unit)
}.drain ++ Stream(ExitCode.Error)
}
} |
@avakhrenev Can you try without object QueueTest extends App {
import ExecutionContext.Implicits.global
Stream.eval(async.boundedQueue[IO, Either[Throwable, Option[Int]]](10)).flatMap { queue =>
queue.dequeueAvailable.rethrow.unNoneTerminate.concurrently(
Stream.constant(1, 128).covary[IO].noneTerminate.attempt.evalMap(queue.enqueue1(_))
).evalMap(_ => IO.unit)
}.run.unsafeRunSync()
} |
This program definitely leaks: object HungMerge extends App {
import ExecutionContext.Implicits.global
val hung = Stream.eval(IO.async[Int](_ => ()))
val progress = Stream.constant(1, 128).covary[IO]
(hung merge progress).run.unsafeRunSync()
} |
Note |
Hm, your program leaks also, or maybe I'm misinterpreting results. I've added println at case State.Unset(waiting) =>
val wu = waiting.updated(id, cb)
State.Unset(wu) -> F.delay[Unit](
if(wu.size > 100)
println(s"Waiters size is: ${wu.size}")
else ()) |
Wait, does In any case, |
@avakhrenev Yeah, I see a slow leak in @SystemFw I'll test non-hung merge now. |
Merging 2 progressing streams does not leak: object ProgressMerge extends App {
import ExecutionContext.Implicits.global
val progress = Stream.constant(1, 128).covary[IO]
(progress merge progress).run.unsafeRunSync()
} |
@mpilquist Probably found the cause, |
Fixed by #1027 |
@avakhrenev Thanks a lot for spotting this, turns out it was a pretty serious problem. |
@mpilquist @SystemFw Thank you for your great work! |
The following program
leaks memory. Here is what Eclipse Momory Analyzer shows:
fs2 version is 0.10.0-M9
The text was updated successfully, but these errors were encountered: