The following Kotlin Native test code uses weak references and manual triggering of garbage collection in the hope of ensuring objects have been reclaimed (rationale: if this works correctly then this mechanism can then be used in more complex scenarios to ensure various components don't hold to references they no longer need. Alternative approaches to achieve this goal are out of scope for this question and will not be accepted as answers, but are welcome in comments!):
import kotlin.test.Test
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertSame
class WeakReferenceTest {
@Test fun weakReference() {
var strong: Any? = Any()
val weak = kotlin.native.ref.WeakReference(strong!!)
kotlin.native.internal.GC.collect()
assertSame(strong, assertNotNull(weak.get()))
strong = null
kotlin.native.internal.GC.collect()
assertNull(weak.get())
}
}
The problem is this test fails: even after losing the strong reference and triggering garbage collection, the last assertion still fails, stating that weak.get()
is not null
but rather still an Any
object.
My question is why this test fails and how I can fix it, or at least how I can go about understanding what's going on there. For example, I don't know if the problem lies within the weak reference or with the garbage collection; is there maybe a way to check whether garbage collection really took place? Or is there a way to examine what the source code got compiled to, and see if there happens to be another reference generated by the compiler which is still in scope (in Why does some garbage not get collected when forcing a GC sweep in Kotlin JVM, depending on seemingly irrelevant factors?, for example, javap -c
was used to detect such issues with Kotlin JVM).
Note that the exact same test code (only using the corresponding Java entities instead of the native ones) does pass on Kotlin JVM:
import kotlin.test.Test
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertSame
class WeakReferenceTest {
@Test fun weakReference() {
var strong: Any? = Any()
val weak = java.lang.ref.WeakReference(strong!!)
System.gc()
assertSame(strong, assertNotNull(weak.get()))
strong = null
System.gc()
assertNull(weak.get())
}
}