Quick answer: StopAllCoroutines leaves resources allocated (a download stream, a UI panel shown) because the coroutine’s “finally” cleanup never ran.

A loading coroutine opens a Stream then StopAllCoroutines is called on scene change; the stream isn’t closed. C# IEnumerator doesn’t honor try/finally on early stop.

Coroutines Are Not Tasks

StopCoroutine simply discards the IEnumerator. Any pending cleanup (try/finally, IDisposable) never runs. Treat coroutines as fire-and-forget for cleanup purposes.

Explicit Cleanup on Cancel

private bool isLoading;
IEnumerator Load() {
    isLoading = true;
    try { // work }
    finally { CleanUp(); isLoading = false; }
}
void OnDisable() { if (isLoading) CleanUp(); }

Belt-and-braces: even if the coroutine is yanked, OnDisable cleans up.

UniTask / Awaitable for Tokens

Use Unity 2023’s Awaitable or UniTask. They support CancellationToken — cooperative cancel that respects finally blocks.

Named Stop, Not Stop-All

Track Coroutine references and stop specifically with StopCoroutine(ref) — reduces collateral damage of stop-all.

Verifying

Cancelling a load mid-flight returns the script to a clean state. No leaked allocations or zombie UI panels.

“StopCoroutine kills the iterator. Cleanup must be explicit in OnDisable.”

Move new async logic to Awaitable + CancellationToken — cleaner cancel semantics and integrates with .NET async patterns.