In Java 9+ with Scala, how to make a Cleanable that can be triggered by `System.gc()`

51 views Asked by At

Considering the following example in Scala 2.13.12 & Java 11:

class CleanableSpike extends AnyFunSpec {

  import CleanableSpike._

  it("triggered by GC") {

    var v = Dummy(inc)
    v = null

    System.gc()

    Thread.sleep(1000)
    assert(count == 1)
  }
}

object CleanableSpike {

  val jvmCleaner = Cleaner.create()

  @transient var count = 0

  val inc = () => count += 1

  case class Dummy(fn: () => Unit) extends AutoCloseable {

    final private val cleanable = jvmCleaner.register(
      this,
      { () =>
        println("\ncleaned\n")
        fn()
      }
    )

    override def close(): Unit = cleanable.clean()
  }
}

When the test is executed, it gave the following error:


org.scalatest.exceptions.TestFailedException: 0 did not equal 1
    at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
    at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
    at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
    at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
    at com.tribbloids.spookystuff.lifespan.CleanableSpike.$anonfun$new$1(CleanableSpike.scala:19)

Clearly, the cleanup function was not triggered, ironically, if I replace the Cleaner implementation with the now-obsolete finalize() function, the test will pass.

What could go wrong here, and what implementation should I use to ensure that the new implementation can have the same capability (namely, to be triggered by System.gc())?

0

There are 0 answers