Daniele Segato
10/22/2018, 3:58 PMby lazy
can cause memory leaks.
Notable one: https://twitter.com/chrisbanes/status/897075635142754305
Is this an old issue that has been solved in recent versions of kotlin or is it still a "gotcha" that the developer has to take care of?
If still a gotcha, any suggestion on how to handle values that might not be initialized? As far as I understand I can't access the delegate directly.Martin Devillers
10/22/2018, 3:59 PMby lazy
some value which depends on a mutable stateview
Daniele Segato
10/22/2018, 4:02 PMprivate class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
initializer = null
after using itby lazy
.Martin Devillers
10/22/2018, 4:08 PMEgor Trutenko
10/22/2018, 4:09 PMMartin Devillers
10/22/2018, 4:10 PMDaniele Segato
10/22/2018, 4:12 PMMartin Devillers
10/22/2018, 4:13 PMEgor Trutenko
10/22/2018, 4:15 PMlazy
is not meant for that, lateinit
isDaniele Segato
10/22/2018, 4:15 PMMartin Devillers
10/22/2018, 4:17 PMlateinit
usually means that you’re loading all your view references at creation, which is something which was initially discouraged because of the overhead (although I’d argue that it’s generally insignificant on modern devices). Using lazy
means that your view references are loaded only when they’re needed.Daniele Segato
10/22/2018, 4:17 PMMartin Devillers
10/22/2018, 4:17 PMlazy
is loading a value which depends on a mutable stateDaniele Segato
10/22/2018, 4:17 PMMartin Devillers
10/22/2018, 4:18 PMDaniele Segato
10/22/2018, 4:19 PMarekolek
10/22/2018, 4:19 PMlateinit var
, or a nullable var
you can recreate the same memory leak from the tweetEgor Trutenko
10/22/2018, 4:20 PMlazy
, are discouraged to apply to poorly architectured frameworks (Android), because of such unexpected behavior and leaks.Martin Devillers
10/22/2018, 4:20 PMDaniele Segato
10/22/2018, 4:22 PMby lazy
in A is never initialized (not used). The initialization lambda hold a reference to instance A.
When A gets destroyed and B created I expect the by lazy to go away and not keep A alive.
B has it's own by lazy.
Is that true?Martin Devillers
10/22/2018, 4:23 PMlazy
will have the same memory lifecycle as the instance in which they were created. Ask yourself whether that’s what your want or not. If the block of lazy
depends on some state of the outer instance which is going to mutate, then the answer is no.,Daniele Segato
10/22/2018, 4:24 PMby lazy
should only have a reference to the fragment and thus shouldn't leak activity A.
when it is initialized it MIGHT leak activity A depending on what value has been initialized to.
This is how I expect it to workMartin Devillers
10/22/2018, 4:25 PMlazy
field in a component like an activity
, then if that activity gets destroyed & garbage collected then the lazy instance will also get released, lambda & value.Daniele Segato
10/22/2018, 4:26 PMMartin Devillers
10/22/2018, 4:26 PMDaniele Segato
10/22/2018, 4:27 PMMartin Devillers
10/22/2018, 4:27 PMDaniele Segato
10/22/2018, 4:31 PMprivate val viewModel: MyViewModel by lazy { ViewModelProviders.of(requireActivity()).get(MyViewModel::class.java)
}
the initialization need the activity (requireActivity()
) to initialize but the MyViewModel
itself has no reference that leak the activity or the fragment.
how is this terrible code?ribesg
10/23/2018, 7:35 AMMartin Devillers
10/23/2018, 8:25 AMlazy
property not having been already initialized when calling it would be terrible