Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix possibly huge memory leak caused by long lived CancellableManagerProvider #213

Merged

Conversation

marclefrancois
Copy link
Member

Description

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

Motivation and Context

In certain realtime application, usage of debounce() on long lived, shared publishers could cause immense memory leaks

How Has This Been Tested?

  • Tested in our application
  • Ran the unit tests

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

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
Copy link
Member

@smatte smatte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change we change the following behavior: if I create a new CancellableManger and the provider has been cancelled then the returned manager needs to be cancelled.

cancellableManager.add(it)
return CancellableManager().also { cancellableManager ->
internalCancellableManagerRef.getAndSet(cancellableManager).cancel()
serialQueue.dispatch {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of the serialQueue is to ensure sequential cancellation of currently returned ref

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This essentially mimicks the CancellableManager internal implementation to be on the safe side

}
}

override fun cancel() {
cancellableManager.cancel()
serialQueue.dispatch {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of the serialQueue is to ensure sequential cancellation of currently returned ref

@marclefrancois marclefrancois merged commit 9b298e5 into master Jan 8, 2024
1 check passed
@marclefrancois marclefrancois deleted the fix/memory_leak_in_cancellable_manager_provider branch January 8, 2024 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants