使用coroutineScope时出现Kotlin协程内存泄漏问题的复现
Kotlin协程coroutineScope导致内存泄漏的原因与修复
问题原因
你碰到的内存泄漏,本质是冗余的coroutineScope + async写法引发的残留引用:
- 你写的
io函数用coroutineScope包裹async(Dispatchers.IO)再await,这种组合完全没必要——async + await在coroutineScope里的行为和withContext(Dispatchers.IO)完全一致,但前者会额外生成一个Deferred对象。 - 由于
io是inline函数,生成大字符串的代码会被内联到async的lambda中,coroutineScope创建的作用域会跟踪这个子协程。 - 当
await完成后,虽然你已经拿到结果返回,但coroutineScope的作用域对象会被外层runBlocking的协程上下文持有(因为Thread.sleep阻塞了主线程,导致runBlocking协程一直处于活跃状态),这个作用域保留着对Deferred的引用,间接持有了大字符串,导致它无法被GC回收。
修复方法
把冗余的coroutineScope + async替换成withContext,既保留切换IO线程的能力,又避免多余的对象引用:
修复后的io函数
suspend inline fun <R> io(crossinline body: suspend () -> R): R = withContext(Dispatchers.IO) { body() }
直接简化runGaqlRequest(如果不需要复用io函数)
suspend fun runGaqlRequest(): List<String> = withContext(Dispatchers.IO) { listOf("A".repeat(300_000_000)) }
补充说明
移除coroutineScope后正常的原因:直接返回大字符串时,没有额外的协程作用域或Deferred对象持有它的引用,当myReport将原列表映射为新列表后,原大字符串失去所有可达引用,自然会被垃圾回收。
内容的提问来源于stack exchange,提问作者Jelmer
相关产品推荐
相关产品推荐

