Skip to content

Commit 73f780c

Browse files
authored
Fix cancelled delayed jobs not being disposed of in TestDispatcher (#3441)
Fixes #3398
1 parent 7d8e275 commit 73f780c

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

kotlinx-coroutines-test/common/src/TestDispatcher.kt

+8-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@ public abstract class TestDispatcher internal constructor() : CoroutineDispatche
3131
/** @suppress */
3232
override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
3333
val timedRunnable = CancellableContinuationRunnable(continuation, this)
34-
scheduler.registerEvent(this, timeMillis, timedRunnable, continuation.context, ::cancellableRunnableIsCancelled)
34+
val handle = scheduler.registerEvent(
35+
this,
36+
timeMillis,
37+
timedRunnable,
38+
continuation.context,
39+
::cancellableRunnableIsCancelled
40+
)
41+
continuation.disposeOnCancellation(handle)
3542
}
3643

3744
/** @suppress */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
import kotlinx.coroutines.*
5+
import kotlinx.coroutines.test.*
6+
import kotlin.test.*
7+
8+
class MemoryLeakTest {
9+
10+
@Test
11+
fun testCancellationLeakInTestCoroutineScheduler() = runTest {
12+
val leakingObject = Any()
13+
val job = launch(start = CoroutineStart.UNDISPATCHED) {
14+
delay(1)
15+
// This code is needed to hold a reference to `leakingObject` until the job itself is weakly reachable.
16+
leakingObject.hashCode()
17+
}
18+
job.cancel()
19+
FieldWalker.assertReachableCount(1, testScheduler) { it === leakingObject }
20+
runCurrent()
21+
FieldWalker.assertReachableCount(0, testScheduler) { it === leakingObject }
22+
}
23+
}

0 commit comments

Comments
 (0)