-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Closed
Labels
Description
I've encountered a memory leak which I believe is caused by a race condition in the coroutine library.
I've simplified the leak down to the following repro code:
private suspend fun <T : Any> ReceiveChannel<T>.receiveBatch(size: Int): List<T> {
return List(size) { receive() }
}
fun main() = runBlocking {
class Thing(val counter: Long /* for debugging on the heap dump */)
val channel1 = produce(capacity = 64) { // from the main thread
(0 until Long.MAX_VALUE).forEach {
send(Thing(it))
}
}
launch(newSingleThreadContext("Channel2")) { // to a single thread (This thread is important! no leak if everything is single threaded)
flow {
while (true) {
emit(channel1.receiveBatch(64))
}
}.collect { }
}
Unit
}
This sample code leaks Thing
s very rapidly
I haven't dug too deep, but one interesting thing is if I inline the code for receive batch, there is no leak. Example:
fun main() = runBlocking {
class Thing(val counter: Long /* for debugging on the heap dump */)
val channel1 = produce(capacity = 64) { // from the main thread
(0 until Long.MAX_VALUE).forEach {
send(Thing(it))
}
}
launch(newSingleThreadContext("Channel2")) { // to a single thread (This thread is important! no leak if everything is single threaded)
flow {
while (true) {
emit(List(64) { channel1.receive() })
}
}.collect { }
}
Unit
}
Tested with kotlin 1.4.30 and coroutines-core 1.4.3