[Edit: I believe this is can be closed as ‘user error’ in reading the Profiler reference counts. Suggestions on the use of GlobalScope were also provided]

It appears that coroutines retain references that prevent garbage collection even in trivial examples.

Consider this Android project

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) GlobalScope.launch(Dispatchers.Default) { backgroundFunction() } } suspend fun backgroundFunction() { val bitmap = Bitmap.createBitmap(4096, 4096, Bitmap.Config.ARGB_8888) withContext(Dispatchers.Main) { findViewById<TextView>(R.id.textView).text = "BITMAP SIZE: ${bitmap.width} x ${bitmap.height}" } } }

A single Activity launches backgroundFunction , which allocates a large local Bitmap . Coroutine context then switches to the main thread to update the TextView with statistics that references bitmap .

Once backgroundFunction has finished we would expect bitmap to be available for garbage collection, but there are several references retained by the coroutine apparatus that prevent this as shown by the memory profiler:

This side-effect is hard to predict or avoid. Am I doing-it-wrong? i.e. is there a canonical way to switch context that I should be using instead that avoids this behaviour?