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())?