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

[Regression] [Android] [Maps] Map locks up after rendering 50 Polylines #20502

Open
mfeingol opened this issue Feb 11, 2024 · 27 comments
Open

[Regression] [Android] [Maps] Map locks up after rendering 50 Polylines #20502

mfeingol opened this issue Feb 11, 2024 · 27 comments
Labels
area-controls-map Map / Maps i/regression This issue described a confirmed regression on a currently supported version migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working

Comments

@mfeingol
Copy link

mfeingol commented Feb 11, 2024

Description

My app has a scenario in which it renders a number of GPX tracks. When this number is relatively large (50), the process hangs and appears to be stuck in an infinite loop. Nothing visible in the managed debugger, but endless trace output like this:

[app.Android] Explicit concurrent copying GC freed 3(31KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 12MB/24MB, paused 243us,39us total 17.795ms
[monodroid-gc] 46192 outstanding GREFs. Performing a full GC!

Steps to Reproduce

Run the repro app. Inside the app, click on the Lots of Polylines option at the bottom of the menu.

If the page renders a map with some lines, then the test succeeded and there is no bug.

If the app hangs with unhappy GC messages, then the bug has been reproduced.

Change the count and steps values in the LotsOfPolylinesPage class to simulate a different number of tracks and number of locations in each track. The app falls over at around 46000 total locations.

Link to public reproduction project repository

https://github.com/mfeingol/repros/tree/master/LotsOfPolylinesRepro

Version with bug

8.0.6

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

8.0.3

Affected platforms

Android

Affected platform versions

13

Did you find any workaround?

No workaround.

Relevant log output

No response

@mfeingol mfeingol added the t/bug Something isn't working label Feb 11, 2024
@jsuarezruiz jsuarezruiz added area-controls-map Map / Maps potential-regression This issue described a possible regression on a currently supported version., verification pending labels Feb 12, 2024
@ghost ghost added the legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor label Feb 12, 2024
@PureWeen PureWeen added the s/needs-repro Attach a solution or code which reproduces the issue label Feb 12, 2024
@ghost
Copy link

ghost commented Feb 12, 2024

Hi @mfeingol. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md

This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

mfeingol added a commit to mfeingol/repros that referenced this issue Feb 12, 2024
@mfeingol
Copy link
Author

Added a repro link: https://github.com/mfeingol/repros/tree/master/LotsOfPolylinesRepro

And now I'm not sure this actually did work in 8.0.3. But it is 100% a regression from Xamarin.Forms, where this same scenario works well.

@ghost ghost added s/needs-attention Issue has more information and needs another look and removed s/needs-repro Attach a solution or code which reproduces the issue labels Feb 12, 2024
mfeingol added a commit to mfeingol/repros that referenced this issue Feb 12, 2024
mfeingol added a commit to mfeingol/repros that referenced this issue Feb 12, 2024
@drasticactions
Copy link
Contributor

@mfeingol Can you create a repo of this working in Xamarin.Forms? That would help track down what changed for why it worked in Forms, but not MAUI.

@drasticactions drasticactions added s/needs-repro Attach a solution or code which reproduces the issue and removed s/needs-attention Issue has more information and needs another look labels Feb 13, 2024
@ghost
Copy link

ghost commented Feb 13, 2024

Hi @mfeingol. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md

This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

mfeingol added a commit to mfeingol/repros that referenced this issue Feb 13, 2024
mfeingol added a commit to mfeingol/repros that referenced this issue Feb 13, 2024
@mfeingol
Copy link
Author

@ghost ghost added s/needs-attention Issue has more information and needs another look and removed s/needs-repro Attach a solution or code which reproduces the issue labels Feb 13, 2024
@mfeingol
Copy link
Author

@drasticactions: sorry to bug, but were you able to make any progress on this issue? It's a pretty critical showstopper for my app, and we're not far away from XF deprecation... Thanks.

@drasticactions
Copy link
Contributor

@drasticactions: sorry to bug, but were you able to make any progress on this issue? It's a pretty critical showstopper for my app, and we're not far away from XF deprecation... Thanks.

I apologize, I'm not on the MAUI Team. It says "Member" as I'm within dotnet. I work on tooling within Visual Studio that depends on MAUI. I'm helping triage, debug, and when I have time, fixing issues for them, but I'm not looking at this. If I was, I would assign myself to it.

So no, I haven't made progress.

@mfeingol
Copy link
Author

@samhouts: sorry to ping you directly, but is there someone on the team I can work with on this? As mentioned above, this is a pretty critical showstopper for my app and we're not far away from XF deprecation... Thanks.

@samhouts samhouts added area/Maps🗺 migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert and removed legacy-area-controls Label, Button, CheckBox, Slider, Stepper, Switch, Picker, Entry, Editor potential-regression This issue described a possible regression on a currently supported version., verification pending labels Mar 1, 2024
@samhouts samhouts removed the s/needs-attention Issue has more information and needs another look label Mar 1, 2024
@samhouts
Copy link
Member

samhouts commented Mar 1, 2024

@jonathanpeppers Is this something you could take a look at and see if there's something obvious we can resolve here? Thanks!!

@jonathanpeppers
Copy link
Member

jonathanpeppers commented Mar 1, 2024

@mfeingol it doesn't say above, were you using Release builds when comparing performance?

If not, you were comparing the JIT vs Interpreter. The interpreter is on by default for Debug builds in .NET 6+, in order to support C# Hot Reload.

More information about this is mentioned here: https://aka.ms/profile-maui#feature-xyz-was-faster-in-xamarinforms

@mfeingol
Copy link
Author

mfeingol commented Mar 1, 2024

@jonathanpeppers: I first observed the problem in release builds on a physical device. I then isolated the repro in the debugger with debug builds. Either way, the scenario works in Xamarin Forms and locks up hard in MAUI.

@jonathanpeppers
Copy link
Member

@mfeingol do you think it's related to the Map control or Polyline?

@mfeingol
Copy link
Author

mfeingol commented Mar 1, 2024

@jonathanpeppers: I replaced Polyline with Polygon with the same number of locations, and observed the same behavior. The issue appears to occur when adding a number of MapElements such as these containing lots of locations, and not specifically/only with Polyline.

@mfeingol
Copy link
Author

mfeingol commented Mar 2, 2024

@jonathanpeppers: also of note, if I move the Polyline logic to a handler and use the native GoogleMap API directly, it works fine. So the problem is definitely in the MAUI maps code.

image

@mfeingol
Copy link
Author

mfeingol commented Mar 3, 2024

Okay, so I think the issue is on https://github.com/dotnet/maui/blob/main/src/Core/maps/src/Handlers/MapElement/MapElementHandler.Android.cs#L103

This sends the GC into a tailspin:

foreach (var position in geoPathMapElement)
{
    polylineOptions.Points.Add(new LatLng(position.Latitude, position.Longitude));
}

While this seems to work more or less okay:

polylineOptions.Add(geoPathMapElement.Select(p =>new LatLng(p.Latitude, p.Longitude)).ToArray());

@jonathanpeppers: maybe worth investigating why the GC can't handle the first pattern?

@jonathanpeppers
Copy link
Member

@mfeingol I don't think there is a problem with the GC here.

If I understand correctly, there is a problem if you do:

  • N Points.Add() calls

But it works if you do:

  • 1 Add() call with an array

It looks to me this would be called N times in the first case, adding the same points over and over?

public static void MapGeopath(IMapElementHandler handler, IMapElement mapElement)

Does that match with the behavior you're seeing?

I'm not a huge fan of the handler architecture as it creates some problems like this one, and also:

@mfeingol
Copy link
Author

mfeingol commented Mar 7, 2024

@jonathanpeppers: the first case isn't adding the same points over and over. It's adding N points one by one vs. adding all of them a batch. Which really shouldn't be a big deal, I guess.

On that note, on closer examination I am no longer confident that the difference I mentioned above is the core problem. I've added a workaround to this issue in my own code that uses the Android-native PolylineOptions directly in a derived mapper instead of using the Maui Map.MapElements property which goes to the native mapper infra. In that workaround, I see identical results (slow and somewhat GC-stressing, but successful) adding points to PolylineOptions one-by-one vs. in an array.

So... I think I may be landing on your conclusion, which is that perhaps MapElementHandler.MapGeopath is being called repeatedly in the pure Maui case, thus generating lots and lots of garbage. Ideally someone with a debug build of Maui's MapElementHandler would look to see whether this is the case.

@jonathanpeppers
Copy link
Member

So... I think I may be landing on your conclusion, which is that perhaps MapElementHandler.MapGeopath is being called repeatedly in the pure Maui case

Yes, it appears to me if you did:

  • Points.Add(1) - MapGeopath creates 1
  • Points.Add(2) - MapGeopath creates 1 (again!) and 2
  • Points.Add(3) - MapGeopath creates 1 (again!), 2 (again!), and 3

To the point CPU and/or memory are quickly exhausted if the number N is decently large.

@mfeingol
Copy link
Author

mfeingol commented Mar 7, 2024

Anecdotally, I set a bp in the decompiled source for MapGeopath, rendered a single GPX track using Maui's Map.MapElements... and the bp was only hit once. So the root cause remains a mystery. :-(

@jonathanpeppers
Copy link
Member

You'd need to put a breakpoint in the handler / MapGeopath() method instead of the BindableProperty.

@mfeingol
Copy link
Author

mfeingol commented Mar 7, 2024

Yeah, I put it after the comment in this MapGeopath() code:

if (handler.PlatformView is PolylineOptions polylineOptions)
{
	// Will throw an exception when added to the map if Points is empty
	if (geoPathMapElement.Count == 0) // <<<--- BP HERE
	{
		polylineOptions.Points.Add(new LatLng(0, 0));
	}
	else
	{
		foreach (var position in geoPathMapElement)
		{
			polylineOptions.Points.Add(new LatLng(position.Latitude, position.Longitude));
		}
	}
}

@RoiChen001
Copy link
Collaborator

Can repro this issue at Android platform on the latest 17.10 preview2.(8.0.14)
GC

@RoiChen001 RoiChen001 added s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed i/regression This issue described a confirmed regression on a currently supported version labels Mar 22, 2024
@MarcelItada
Copy link

Hello, I also really need this solution.

I had an app made in "Kodular" where I inserted line by line in a "foreach" A[i] to B[i], it was capable of compiling more than a thousand points easily on the Google Maps,
however, in .NET 8 MAUI I can't do it the same way.
In MAUI, it's necessary that all points are in sequence so that the "mappy.MapElements.Add(polylines);" function is executed only once, and it also instantly loads all the lines, the problem: I don't have the logical sequence of point to point in the database, as I mentioned before, I have a table with 4 fields, Latitude1, Longitude1, Latitude2, Longitude2, to insert point by point I need to execute a "foreach" of several mappy.MapElements.Add(polylines[i]); that inserts multiple instances of the polylines.

Note: instantiating more than a thousand points is very fast, less than 1 second,
foreach (var p in points)
polylines[i] = new Microsoft.Maui.Controls.Maps.Polyline
{
StrokeWidth = 10,
StrokeColor = Color.FromRgb(0, 159, 195)
};
polylines[i].Geopath.Add(new Location(p.LAT_1, p.LONG_1));
polylines[i].Geopath.Add(new Location(p.LAT_2, p.LONG_2));

The function that takes about 1 minute for 1000 points is the
mappy.MapElements.Add(polylines[i]);

Please create a new function similar to the one below:
AddPolylineToMap(new Location(LAT_1, LNG_1), new Location(LAT_2, LNG_2));

@jsuarezruiz
Copy link
Contributor

A workaround could be, only render the polylines in the visible region, or reduce the number of lines (500 in the sample) from every Polyline. Could use the Douglas-Peucker algorithm for example.

@mfeingol
Copy link
Author

A workaround could be, only render the polylines in the visible region, or reduce the number of lines (500 in the sample) from every Polyline. Could use the Douglas-Peucker algorithm for example.

We shouldn't have to apply a complex workaround like this to address a regression in functionality in .NET MAUI vs Xamarin Forms.

@MarcelItada
Copy link

MarcelItada commented May 25, 2024

A workaround could be, only render the polylines in the visible region, or reduce the number of lines (500 in the sample) from every Polyline. Could use the Douglas-Peucker algorithm for example.

Hello, jsuarezruiz.

Thank you for the tip about the "Douglas-Peucker" algorithm; I wasn't aware of it. I created my own algorithm in a simple way by searching for the nearest point, similar to DBSCAN. Some points in my dataset have a final coordinate equal to the starting coordinate of the next point; however, when there are elements between the points, they usually have a distance of up to 15 meters.

I work at an electricity distribution company and I use this to plot our distribution network cables on Google Maps. I limited it to 270 polygon groups, but sometimes it fails if the polygon is too large (with many points). I am not able to plot all our "feeder networks" because some are too large.

There are several points where MAUI needs improvement, such as changing the colors of the pins and custom icons. Perhaps the solution is to migrate to another framework until MAUI MAPS is more mature.

[](WhatsApp 2024-05-25)

@SupermindPT
Copy link

SupermindPT commented May 28, 2024

Douglas-Peucker

You can change the color of the pins and set custom icons of the map. More information here : Customize Map Pins in .NET MAUI by vladislavantonyuk

There other maps available, like Mapsui , although I do not recommend it for beginners because documentation is lacking.

Maui.GoogleMaps is a pretty nice nuget package that offers interesting functionality as alternative to Maui.Maps.

One advantage of MAUI, similar to Xamarin, is the possibility to bind native Java Libraries. This means you can integrate any native Android Java library into your app. There are countless of native Android libraries, for sure you can find something that does what you need. But most times integrating those libraries is a diffcult task.

@jsuarezruiz jsuarezruiz added this to the .NET 8 + Servicing milestone Jun 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-map Map / Maps i/regression This issue described a confirmed regression on a currently supported version migration-compatibility Xamarin.Forms to .NET MAUI Migration, Upgrade Assistant, Try-Convert platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

10 participants