Durgan McBroom
07/03/2025, 8:35 AMMyCustomType
to be garbage collected immediately after callThis
completes (as happens without coroutines), however this does not happen.
class MyCustomType(val str: String)
suspend fun callThis() {
val type = MyCustomType("Test")
delay(100)
println(type.str)
}
suspend fun secondCall() {
delay(100)
}
@Test
fun `Testing coroutines`() {
runBlocking {
callThis()
secondCall()
}
}
Looking at the IntelliJ Memory profiler, the object is not removed until after secondCall
. Im wondering why this memory needs to persist into the execution of the parent function? The value does not get garbage collected until after the next suspend call or after the runBlocking
block has finished. In a scenario where a suspending function like this uses a lot of memory across coroutine boundary and then passes execution to a blocking program (still inside runBlocking) I could see a memory leak being caused, though I might be missing something.Youssef Shoaib [MOD]
07/03/2025, 9:09 AMsuspend
, the JIT realizes that type
never escapes its context, and hence removes it immediately, while with delay
, the object does get stored somewhere (namely in the state machine for callThis
), and hence such an optimization doesn't happen immediately. This shouldn't affect anything at all thoughYoussef Shoaib [MOD]
07/03/2025, 11:57 AMcallThis
state machine instance between callThis
and right before secondCall
. This would only apply basically if callThis
was inlined.
Also, that issue is solved, and I'm pretty sure I've observed correct behaviour in this circumstance in my experiments.ephemient
07/03/2025, 12:01 PMephemient
07/03/2025, 12:05 PMephemient
07/03/2025, 12:10 PMDurgan McBroom
07/03/2025, 6:17 PMprintln
method in this example:
@Test
fun `Late night test`() {
runBlocking {
callThis()
System.gc()
println("Here") // Object still in memory
}
}
Is this what you meant?Durgan McBroom
07/03/2025, 6:21 PMDurgan McBroom
07/03/2025, 6:35 PM