Skip to content

fix(android): Leaking listeners#118

Merged
oblador merged 8 commits intooblador:masterfrom
mateuuszzzzz:mateuuszzzzz/fix-memory-leaks
Oct 23, 2025
Merged

fix(android): Leaking listeners#118
oblador merged 8 commits intooblador:masterfrom
mateuuszzzzz:mateuuszzzzz/fix-memory-leaks

Conversation

@mateuuszzzzz
Copy link
Contributor

@mateuuszzzzz mateuuszzzzz commented Sep 30, 2025

This PR fixes three leaks of listeners:

  1. Extracted listener that waits for CONTENT_APPEARED and RELOAD to a constant to prevent leak when module is invalidated. Now we remove this listener in invalidate.
  2. RNPerformance.removeListener had an incorrect condition that prevented listeners from being removed.
  3. Extracted another listener that is added on startup to prevent multiple identical listeners from being added. Since getPackages can be called multiple times in React Native, the PerformancePackage constructor may also be invoked multiple times, resulting in several identical listeners being added as different instances. ReactMarker prevents duplicates only when the same instance is added, so extracting the listener to a static constant resolves this issue.

Additionally I changed onCatalystInstanceDestroyed to invalidate, because previous method is deprecated.

@mateuuszzzzz mateuuszzzzz marked this pull request as ready for review October 9, 2025 11:50
Comment on lines +90 to +94
private void setupMarkerListener() {
ReactMarker.addListener(
contentAppearedListener
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need a separate method for it :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, I wanted to make this look similar to setupNativeMarkerListener which was already in the codebase

// Fix new arch runtime error
public void addListener(String eventName) {

ReactMarker.removeListener(contentAppearedListener);
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we remove the other listener too?

Copy link
Contributor Author

@mateuuszzzzz mateuuszzzzz Oct 13, 2025

Choose a reason for hiding this comment

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

startupMarkerListener is specific, because once we add it to ReactMarker (singleton) it can stay there through the whole app lifetime.

I.e.:

  1. We add it once (by storing it in a static constant, ReactMarker will know that this listener has already been added, so it won’t add it again, preventing duplication when PerformancePackage constructor is called multiple times).
  2. We don’t need to remove it in invalidate because this listener isn’t bound to the native module’s lifetime.

@mateuuszzzzz
Copy link
Contributor Author

Hi @oblador! Would you have some time to review this PR? 🙏

Copy link
Owner

@oblador oblador left a comment

Choose a reason for hiding this comment

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

I had been avoiding migrating to invalidate to keep bw compatibility, but since it's been there since 0.74 I think it should be fine to drop it now.

@oblador oblador merged commit 5fc0408 into oblador:master Oct 23, 2025
6 checks passed
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.

3 participants