-
Notifications
You must be signed in to change notification settings - Fork 502
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
Fixing memory leaks #706
Fixing memory leaks #706
Conversation
# Conflicts: # mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @AAverin, thanks for your work on this issue, as well as reporting your findings in #389.
Even though this chagne probably does fix the issue, it contains a lot of unnecessary changes that are not needed for this fix, and only make the code less readable, and some others that are related to other issues. I am not comfortable accepting all of these changes.
I think the core issue here is a single reference (or two) which is kept longer than it needs to be, and my guess is that it is the method channel call handler, and maybe the platform instance kept around in MapboxGlPlatform._instances
.
I have submitted a PR to address the latter in #710, so maybe you could try just applying method handler change on top of that to see if it resolves the leak?
mapbox_gl_platform_interface/lib/src/method_channel_mapbox_gl.dart
Outdated
Show resolved
Hide resolved
@shroff I was working on top of my other branch that had some fixes applied already. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to agree with @shroff. MapboxGlPlatform.getInstance(_id).dispose();
should be all that is needed. Flutter/dart will properly free any internal objects such as onSymbolTapped
as long as the object holding it is destroyed.
In general manually disposing is only needed to get rid of things that are not directly part of the widgets state.
I will try that other branch once I am back from vacation end of next week and see if it will resolve the leak. Another issue that complicates debugging memory is that flutter itself seems to be leaking widget instances even in the latest version of the engine. I have created flutter/flutter#91508 already and there was another issue where something similar was tracked. Big issue I have right now is #703, and that could be related to some memory leaks. |
Dispose all potential leaks: platform channel, platform callbacks, controller and any callbacks that could be set from outside
I have merged #710 into this branch and did some more investigation and testing for leaks. |
I think the other place that is keeping a reference is the method call handler, which you nulled out in dispose. Maybe try only that on top of #710 |
@shroff you are right that this was the main leak, but doing only that was not enough, I still saw leaks in memory profiler. |
@AAverin thanks again for putting in the work into this. Can you tell what is holding on to this reference? Also, could you share some minimal code that can repro this leak and how you're detecting it? I'd like to play around with it a little bit and really understand how the leak is happening. |
@shroff I got sick so it will take me some time. I think what's leaking is that callbacks like onMapClick and others passed into Mapbox instance are never cleared. It's common to reference MapboxContorller in those methods to interact with the map. So either this results in holding reference that prevents clearing or a known issue in flutter where outside context gets locked in the inner methods resulting in a leak. |
# Conflicts: # lib/src/controller.dart
@shroff Because I couldn't reproduce leaks on a clear sample I have removed some of the code |
@shroff I was about to finish with PR and decided to run my sample again after merging with master. Here is the sample. Please make sure there is some mapbox key set in Android Manifest when testing on Android. Open the sample app, click on FAB to go to map screen, then go back. Repeat a few times.
|
@AAverin can you clean up this branch so that it only contains the changes that are required to fix the memory leeks on master? |
@felix-ht I did, from my perspective. |
I can re-merge with master because the other code for style comes from another branch that was already merged #690 |
@@ -278,4 +278,7 @@ abstract class MapboxGlPlatform { | |||
throw UnimplementedError( | |||
'getMetersPerPixelAtLatitude() has not been implemented.'); | |||
} | |||
|
|||
void dispose() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might want to convert this to be abstract
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The class is abstract already
@AAverin if this significantly reduces the number of leaks i would be all for merging it. Or worded differently: does this fix some(most) of the leaks? (as opposed to the current master that had the id based instances removed) |
From my perspective no leaks should be present in code so if this fixes at least one it should already go in. |
* Cherry-pick upstream#706 (Fixing memory leaks) flutter-mapbox-gl/maps#706 Co-Authored-By: Anton Averin <1481332+AAverin@users.noreply.github.com>
Resolved #389 by clearing everything possible on the MapboxMapController. PR also includes some code from #690 that is necessary for iOS to work.
The main culprit for the leak was onStyleLoadedCallback function assigned when MapboxMapController was initialised and never cleared, keeping a hold on MapboxMap instance through
_widget
variable.Additionally, MapboxGLPlatform was leaking instances because they were added to the internal list and never removed.
While all these leaks would never bother if you have only single map in the app, like in the sample apps, they clearly start bringing issues when you have lots of smaller maps on different screens.