Select to view content in your preferred language

.NET 8 / MAUI 8: Big memory leak in MapView on Android introduced

5651
30
Jump to solution
01-19-2024 11:00 AM
Labels (3)
SokoFromNZ
Frequent Contributor

Hello.

The current ArcGIS Runtime v200.3.0 with the current .NET Maui from VS 17.8.5 has a big memory leak which causes our app to crash on a real world Android device just after a few page changes to the map.

I can reproduce this behavior on any real world device. There the app crashes. The emulator though just allocates more and more memory of course.

I have created two simple apps (see ZIP file).
One is MAUI8+v200.3.0 (Map8 in the video).
One is MAUI7+v200.2.0 (Map7 in the video).

You clearly see the memory of the process qemu-system-x86_64.exe (Android Emulator) go up each time the loaded map gets displayed again by almost 1 GByte on the Map8 app.

On the Map7 app it almost stays the same (On the very top of the video you see the Task Manager with the process, CPU and Memory Usage):

All both apps are doing is creating a map and loading 44 KMZ files with a total of 10MByte. Here is the MainPage.xaml.cs:

 

using System;
using System.Threading.Tasks;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Ogc;
using Microsoft.Maui.Controls;
using Map = Esri.ArcGISRuntime.Mapping.Map;

namespace ArcGISTry1;

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        // Create the UI, setup the control references and execute initialization
        _ = Initialize();
    }

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
    private async Task Initialize()
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
    {
        // Set map to mapview
        MyMapView.Map = new Map(BasemapStyle.OSMLightGray)
        {
            InitialViewpoint = new Viewpoint(new MapPoint(11.406534, 47.719954, SpatialReferences.Wgs84), 6000)
        };

        MyMapView.Loaded += OnLoaded;
    }

    private async void OnLoaded(object? sender, EventArgs e)
    {
        for (var i = 0; i <= 43; i++) {
            var dataset = new KmlDataset(new Uri($"http://soko.yourweb.de/kmz/MemoryLeak/{i:00000}.kmz"));
            await dataset.LoadAsync();
            var kmlLayer = new KmlLayer(dataset);
            MyMapView.Map!.OperationalLayers.Add(kmlLayer);
        }
    }
}

 

Those KMZ files are from my production environment and get loaded like this every day by the users which currently use MAUI7.

Please look at this as soon as you can as I have to do another release in February and with this big bug its impossible to do so.

A workaround would help as well if no pre-release is possible until then.

As mentioned already: This is not an Emulator issue! Its just a good and easy way to show/see the problem. After switching pages on the emulator for 1-2 minutes the process used more than 64GByte on my machine.
On the real device (4 and 6 GByte) it only survies a couple a switches....

thanks

Soko

PS: on the Map7/MAUI7 app you have to move your finger over the map after switching back from the notes-page. This is a known bug in ArcGIS 200.2.0 (see my other post for this).

0 Kudos
30 Replies
TomGassner
Emerging Contributor

please contact me t.gassner@mysynergis.com (Esri Distributor Austria). One of our developer already showed one of Esri Inc. developer how you can reproduce it. We can do it  again for you.

we have to help SokoFromNZ urgently, because it is very critical for him and the bug still exist. see also BUG-000164907 

 

thank you

Thomas

0 Kudos
SokoFromNZ
Frequent Contributor

Thanks for looking into this. So you have tried my apk (http://soko.yourweb.de/com.companyname.memoryleak8-Signed.apk) and it does not crash an real hardware? Can you give me more information? As you can see in the video http://soko.yourweb.de/Hardware.mp4 its definetly happening on all the hardware my customer uses.

Furthermore: I'm not able to release any new versions of the app since this leak!

As a software developer for more then 25 years I know your side if the issue is not reproduceable. Its a pain. In the end though...it was always explainable...

So maybe its a language/culture setting that plays into here? Or anyhting else...

I will spent any amount of time to find the issue, but therefore I need more info from your side here how you tested in detail.

thanks

0 Kudos
dotMorten_esri
Esri Notable Contributor

We've tried on a number of devices and don't observe a crash from flipping back and forth.

Any chance you could retry with v200.5 ? We made some changes to how the view pauses and resumes to address another issue, that could have an impact on this.

Also for giggles, could you on each Page.Loaded event add the following code, just to rule in/out we're not just hitting a lazy garbage collection issue:

GC.Collect();
GC.WaitForPendingFinalizers();

Wrt to the memory profiler you asked about, Android studio was used. More details here:
https://developer.android.com/studio/profile/memory-profiler
You should be able to see what is using up all that memory and that might lead us closer to the root problem and why you can reproduce when we can't.

I'm also curious about the code you added:
MyMapView.InvalidateMeasureNonVirtual(Microsoft.Maui.Controls.Internals.InvalidationTrigger.Undefined);
Was that to work around a resume issue? (that's been fixed in 200.5 btw).

0 Kudos
TomGassner
Emerging Contributor

Hi, we tested it with 200.5 and also with addition code as you mention. We did that also before with our testing... If you @dotMorten_esri  wanna see, how you can reproduce the issue, please contact me and we can make a call with my developer. thank you

0 Kudos
dotMorten_esri
Esri Notable Contributor

Were you able to use the Android Studio memory profiler? Did the code changes or version have any effect? What about the code you added that I asked about?

I've seen the video showing the repro steps and followed them. Is there anything beyond that, that the video doesn't catch that we're missing?

0 Kudos
TomGassner
Emerging Contributor

We used a other method to profile. Android Studio was not in use. But this is not the reason... Code changes has no effect on this. our testing code is also without the code you asked. Today we testet with 200.5 on a android device and we got after 5 switches the memory leak which cause a app crash. 

 

Please lets have a Teams Call and we can do it in short way to demonstrate this issue. please send me a email to t.gassner@mysynergis.com or just send me a message  via Teams. thank you

SokoFromNZ
Frequent Contributor

Hi guys,

I've just tested this with the new .NET9 and current Runtime 200.5.0: The memory leak still exists!

I've attached my source code for .NET9.

@dotMorten_esri @TomGassner : What is your status here? I hope you see that this issue doesn't solve itself (or by Microsoft).

I don't know what to tell my customers anymore 😞

Soko

0 Kudos
SokoFromNZ
Frequent Contributor

@dotMorten_esri @TomGassner : Runtime 200.6.0 is released. The memory leak is still present in this version as well 😞

0 Kudos
SokoFromNZ
Frequent Contributor

With version 200.7 of the .NET Runtime I can finally report the fix of this bug. Thanks to all who helped here to finally get rid of this crucial bug for our application.

Maybe you guys want to share some details as I'm curious about the complexity of this bug

MatveiStefarov
Esri Contributor

Hi Soko!  If you are curious about the technical details:

GeoView uses OpenGL ES to render on Android, which is quite sensitive to context and order of operations.  I ended up committing three fixes to stop the memory leak:

  1. GeoView's "StopRendering" function, which needed a current EGL context, was sometimes called from the wrong thread, which prevented some resources from being released.
  2. In some scenarios where a rendering surface is being recreated, the old EGLSurface was not destroyed before a new one is created. This leaked a Java handle to an EGLSurface which also prevented some resource cleanup.
  3. In addition, release of some resources was delayed until .NET garbage collection hit because we did not dispose C# wrappers over EglContext/EglDisplay/EglSurface/EglSurfaceTexture eagerly enough. Adding proactive dispose calls helped release memory sooner and lower peak resource use.

The leak did not disappear until 1 and 2 were fixed, and even then the reproducer was flaky until problem 3 was fixed.  All along, debugging was complicated because it involved code in three different languages (C#, Java, C++) with two different garbage collectors that have a tendency to create reference cycles across interop boundaries.

So, I am very glad to finally have it fixed! 🙂