wasyl
02/04/2021, 8:59 PMFoo
and a factory which always returns the same value as long as the previous one is still referenced:
class Foo
class FooFactory {
var fooRef: WeakReference<Foo>? = null
fun get() = fooRef?.get() ?: Foo().also { fooRef = WeakReference(it) }
}
So far so good. Now I have spec which should assert that the objects are in memory as expected. This overall might be tricky because GC is not very deterministic, but it’s stable enough:
class TestSpec : DescribeSpec() {
private val fooFactory = FooFactory()
init {
describe("foo") {
var foo: Foo? = fooFactory.get()
// println(foo)
describe("bar") {
gc()
fooFactory.fooRef?.get() shouldNot beNull()
foo = null
gc()
fooFactory.fooRef?.get() should beNull()
it("should do something") {
println("Done")
}
}
}
}
override fun isolationMode() = IsolationMode.InstancePerLeaf
}
And now the tricky part: if the println(foo)
is commented out, the test works. But if it’s not, then the test fails at the should beNull()
line. Apparently something is holding it. I checked in IJ’s memory tool and it looks like it’s just a variable being kept, but I have no clue why and how this would happen. Also I expect that with InstancePerLeaf
this entire thing is executed just once anyway, as there’s only one leaf. Any ideas?wasyl
02/04/2021, 8:59 PMwasyl
02/04/2021, 9:18 PMsam
02/04/2021, 9:19 PMsam
02/04/2021, 9:19 PMwasyl
02/04/2021, 9:22 PMsam
02/04/2021, 9:22 PMsam
02/04/2021, 9:23 PMwasyl
02/04/2021, 9:24 PMprintln
and don’t crash without it. I originally kept InstancePerLeaf
because it was relevant in couple issues I had before, but not this timesam
02/04/2021, 9:24 PMsam
02/04/2021, 9:25 PMwasyl
02/04/2021, 9:25 PMsam
02/04/2021, 9:26 PMsam
02/04/2021, 9:27 PMsam
02/04/2021, 9:28 PMvar foo: Foo? = fooFactory.get()
sam
02/04/2021, 9:28 PMwasyl
02/04/2021, 9:28 PMwasyl
02/04/2021, 9:28 PMfoo = null
, so the only (and last) strong reference to Foo is gonesam
02/04/2021, 9:29 PMwasyl
02/04/2021, 9:29 PMprintln
before 😕sam
02/04/2021, 9:29 PMsam
02/04/2021, 9:29 PMwasyl
02/04/2021, 9:30 PMgc()
such that when it returns, GC should’ve already ran. And there’s no reason (although I haven’t checked the spec) for JVM to keep objects without strong references when GC happenssam
02/04/2021, 9:31 PMwasyl
02/04/2021, 9:31 PMprintln(foo)
change the gc behavior?sam
02/04/2021, 9:31 PMsam
02/04/2021, 9:31 PMwasyl
02/04/2021, 9:32 PMfoo = null
to before the describe("bar")
, then the instance gets back to being GCed every time:wasyl
02/04/2021, 9:32 PMsam
02/04/2021, 9:32 PMsam
02/04/2021, 9:33 PMsam
02/04/2021, 9:33 PMinit {
describe("foo") {
var foo: Foo? = fooFactory.get()
println(foo)
foo = null
describe("bar") {
gc()
fooFactory.fooRef?.get() shouldBe null
it("should do something") {
println("Done")
}
}
}
}
sam
02/04/2021, 9:34 PMsam
02/04/2021, 9:34 PMsam
02/04/2021, 9:34 PMsam
02/04/2021, 9:35 PMsam
02/04/2021, 9:35 PMinit {
describe("foo") {
var foo: Foo? = fooFactory.get()
println(foo)
describe("bar") {
foo = null
gc()
it("should do something") {
println("Done")
}
}
}
describe("foo2") {
fooFactory.fooRef?.get() shouldBe null
}
}
wasyl
02/04/2021, 9:35 PMwasyl
02/04/2021, 9:36 PMwasyl
02/04/2021, 9:36 PMwasyl
02/04/2021, 9:37 PMsam
02/04/2021, 9:37 PMwasyl
02/04/2021, 9:37 PMwasyl
02/04/2021, 9:40 PMLeoColman
02/05/2021, 12:24 AMLeoColman
02/05/2021, 12:24 AMwasyl
02/05/2021, 7:18 AMLeoColman
02/05/2021, 12:28 PM