Description
GlobalScope
is provided by kotlinx.coroutines as a convenient way to launch coroutines, without the need to have a proper scope.
But using GlobalScope
may easily result in leaking coroutines continuing to be executed even after the end of life of the component which started the coroutine.
The recommended approach is to define scopes either making classes implement CoroutineScope
or by useing coroutineScope
in suspending function.
Snippet of non-compliant Code
Class with defined life-cycle:
class ViewComponent {
init {
GlobalScope.launch(Dispatchers.Main) {
while(isActive) { updateUI() }
}
}
}
Suspending function:
suspend fun parallelDecomposition(): Result {
val part1 = GlobalScope.async { computePart1() }
val part2 = GlobalScope.async { computePart2() }
return combine(part1.await(), part2.await())
}
Snippet of Compliant Code (fixing the above non-compliant code)
Class with defined life-cycle:
class ViewComponent : CoroutineScope {
private val job = Job()
override val coroutineContext = job + Dispatchers.Main
init {
launch {
while(isActive) { updateUI() }
}
}
fun dispose() {
job.cancel()
}
}
Suspending function:
suspend fun parallelDecomposition(): Result = coroutineScope {
val part1 = async { computePart1() }
val part2 = async { computePart2() }
return combine(part1.await(), part2.await())
}
External references
Official kotlin coroutine guide (https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/basics.md#structured-concurrency) states:
When we use
GlobalScope.launch
we create a top-level coroutine. Even though it is light-weight, it still consumes some memory resources while it runs. If we forget to keep a reference to the newly launched coroutine it still runs. […] Instead of launching coroutines in the GlobalScope, […] we can launch coroutines in the specific scope of the operation we are performing.
Here is also a good article about structured concurrency written by Roman Elizarov (maintener of kotlinx.coroutines): Structured concurrency. Today marks the release of a version… | by Roman Elizarov | Medium
Type : Bug
Using GlobalScope
may result in memory leaks.
I would personally set the default severity to “Major”
Tags
performance, multi-threading, bad-practice, design