Mark
03/25/2020, 12:08 PMinit {
someInstance.someVal = { someHelper.someFun(it) }
}
and LeakCanary hinted that this was causing a leak, so (as a complete stab in the dark) I switched to using a method reference and the leak seemed to go away. Can anyone explain why such a seemingly minor change could fix a leak, please?
init {
someInstance.someVal = someHelper::someFun
}
mzgreen
03/25/2020, 1:54 PMZach Klippenstein (he/him) [MOD]
03/25/2020, 3:06 PMsomeHelper
from your lambda, presuming someHelper
is a property on your class, that lambda code is actually doing this.someHelper.someFun
. Ie your lambda "captures" a reference to this
, so it can call someHelper
on it later. This is probably where the leak comes from. You can verify this is what's happening by looking at the Kotlin bytecode generated for this (in intellij, "Show kotlin bytecode").
In the second case, the code is getting the someHelper
reference eagerly and storing it in the bound method reference. It's effectively doing:
val someHelperCapture = this.someHelper
{ someHelperCapture.someFun(it) }
Because this lambda no longer references this
, the compiler doesn't bother storing a reference to it in the lambda object (ie. it's not captured), so you're no longer leaking it.Mark
03/26/2020, 2:45 AMsomeHelper
is a private val (declared in constructor). When I change to using a method reference, I see that it can be a private val
-less constructor argument indicating (as you say) that it is being referenced directly as opposed to via this
before. Not sure why the compiler doesn’t reference it directly anyway though (since it’s neither a var nor has a custom getter).Zach Klippenstein (he/him) [MOD]
03/26/2020, 4:18 AM