import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.concurrent.duration.Duration

/** This test uses recursive calls to Future.flatMap to create arrays whose
 *  combined size is slightly greater than the JVM heap size. A previous
 *  implementation of Future.flatMap would retain references to each array,
 *  resulting in a speedy OutOfMemoryError. Now, each array should be freed soon
 *  after it is created and the test should complete without problems.
 */
object Test {
  def main(args: Array[String]): Unit = {
    def loop(i: Int, arraySize: Int): Future[Unit] = {
      val array = new Array[Byte](arraySize)
      Future.successful(i).flatMap { i =>
        if (i == 0) {
          Future.successful(())
        } else {
          array.size // Force closure to refer to array
          loop(i - 1, arraySize)
        }

      }
    }

    val arraySize = 1000000
    val tooManyArrays = (Runtime.getRuntime().totalMemory() / arraySize).toInt + 1
    Await.ready(loop(tooManyArrays, arraySize), Duration.Inf)
  }
}
