Skip to content

Commit

Permalink
Fix forever growing cancellable Manager
Browse files Browse the repository at this point in the history
A long lived CancellableManagerProvider could easily end up with very many “cancelled” Cancellable in it’s internal CancellableManager because this is only cleared when the Provider itself is cancelled.

This can cause huge memory leaks in some cases, for example in the DebounceProcessor

Since there is only ever one “not cancelled” CancellableManager provided by the CancellableManagerProvider, there is actually no need to keep the previously provided, now cancelled, CancellableManager.

We now simply use the internalCancellableManagerRef.

Also took the oportunity to make cancelPreviousAndCreate hopefully atomic be exposing and using getAndSet on AtomicReference
  • Loading branch information
marclefrancois committed Jan 8, 2024
1 parent d633db0 commit 52b09e3
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class AtomicReference<T>(value: T) {
fun compareAndSwap(expected: T, new: T): T {
return if (compareAndSet(expected, new)) new else value
}

fun getAndSet(new: T): T {
return atomicValue.getAndSet(new)
}
}

fun <T> AtomicReference<T>.setOrThrow(new: T) = setOrThrow(value, new)
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@ package com.mirego.trikot.streams.cancellable
import com.mirego.trikot.foundation.concurrent.AtomicReference

class CancellableManagerProvider : Cancellable {
private val cancellableManager = CancellableManager()
private val internalCancellableManagerRef = AtomicReference(CancellableManager())

fun cancelPreviousAndCreate(): CancellableManager {
internalCancellableManagerRef.value.cancel()
return CancellableManager().also {
internalCancellableManagerRef.setOrThrow(internalCancellableManagerRef.value, it)
cancellableManager.add(it)
fun cancelPreviousAndCreate(): CancellableManager =
CancellableManager().also {
internalCancellableManagerRef.getAndSet(it).cancel()
}
}

override fun cancel() {
cancellableManager.cancel()
internalCancellableManagerRef.value.cancel()
}
}

0 comments on commit 52b09e3

Please sign in to comment.