Mapsui
Mapsui copied to clipboard
Xamarin.iOS app freezes while navigating
I've created a Xamarin.Forms app containing Mapsui map with 1 graphics layer. When testing the iOS version on IPhone a complete app freeze can happen while navigating the map.
I've made a project to reproduce, see project 'MemoryProvider' (branch bug/getfeaturesinview_not_called/) in the samples/Mapsui.Samples.MemoryProvider folder. Project under test is MemoryProvider.iOS. Note, in this branch HasFling is set to false.
Its not easy to reproduce, its just a matter of continuous pan and zoom action's while graphic layer is visible (layer has MaxVisible defined), normally within 50 map actions the freeze happens.
Some more observations:
- just a map without the graphics layer: no freeze happens (so far);
- settings like map.RotationLock and map.MyLocationEnabled don't influence the app freeze.
For completeness, an screenshot after freeze. Note the graphics on the right/bottom side stopped drawing.
Could you try, what's happening if you use MapControl instead of MapView? Perhaps you have to remove some special things (like MyLocationLayer) but it would be interesting, if this chances something.
Good suggestion, it still happens when changing mapsui:MapView to mapsui:MapControl in MainPage.xaml. But the freeze seems to occur less frequently.
Crash log from phone:
Date/Time: 2021-09-05 09:52:52.5998 +0200
Launch Time: 2021-09-05 09:52:03.1987 +0200
OS Version: iPhone OS 14.7.1 (18G82)
Release Type: User
Baseband Version: 4.04.00
Report Version: 104
Exception Type: EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d
Termination Description: SPRINGBOARD, <RBSTerminateContext| domain:10 code:0x8BADF00D explanation:scene-update watchdog transgression: application<com.mapsui.MemoryProvider>:59325 exhausted real (wall clock) time allowance of 10.00 seconds | ProcessVisibility: Background | ProcessState: Running | WatchdogEvent: scene-update | WatchdogVisibility: Background | WatchdogCPUStatistics: ( | "Elapsed total CPU time (seconds): 4.980 (user 4.980, system 0.000), 8% CPU", | "Elapsed application CPU time (seconds): 0.386, 1% CPU" | ) reportType:CrashLog maxTerminationResistance:Interactive>
Triggered by Thread: 0
Thread 0 name: tid_103 Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x00000001aebdd908 0x1aebda000 + 14600
1 libsystem_kernel.dylib 0x00000001aebdcd0c 0x1aebda000 + 11532
2 IOKit 0x000000018d3c9bb8 0x18d34e000 + 506808
3 IOKit 0x000000018d355c94 0x18d34e000 + 31892
4 IOGPU 0x00000001bd8279fc 0x1bd817000 + 68092
5 IOGPU 0x00000001bd821fd8 0x1bd817000 + 45016
6 IOGPU 0x00000001bd818a9c 0x1bd817000 + 6812
7 AGXMetalA11 0x00000001cc3cb298 0x1cc38c000 + 258712
8 AppleMetalGLRenderer 0x00000001cb7c7364 0x1cb7c5000 + 9060
9 AppleMetalGLRenderer 0x00000001cb7c7480 0x1cb7c5000 + 9344
10 AppleMetalGLRenderer 0x00000001cb7d3138 0x1cb7c5000 + 57656
11 GLEngine 0x00000001b468ff44 0x1b4668000 + 163652
12 GLEngine 0x00000001b468feb0 0x1b4668000 + 163504
13 libSkiaSharp 0x000000010b3c87c8 0x10b114000 + 2836424
14 libSkiaSharp 0x000000010b2daf38 0x10b114000 + 1863480
15 libSkiaSharp 0x000000010b3460dc 0x10b114000 + 2302172
16 libSkiaSharp 0x000000010b307ce8 0x10b114000 + 2047208
17 libSkiaSharp 0x000000010b3459b4 0x10b114000 + 2300340
18 libSkiaSharp 0x000000010b2e0134 0x10b114000 + 1884468
19 libSkiaSharp 0x000000010b2ea1dc 0x10b114000 + 1925596
20 libSkiaSharp 0x000000010b2d1cf4 0x10b114000 + 1826036
21 libSkiaSharp 0x000000010b2d185c 0x10b114000 + 1824860
22 libSkiaSharp 0x000000010b2d2048 0x10b114000 + 1826888
23 libSkiaSharp 0x000000010b2f5824 0x10b114000 + 1972260
24 libSkiaSharp 0x000000010b38f17c 0x10b114000 + 2601340
25 MemoryProvider.iOS 0x00000001096cf9dc 0x104cf4000 + 77445596
26 MemoryProvider.iOS 0x0000000109559fe4 0x104cf4000 + 75915236
27 MemoryProvider.iOS 0x00000001094e78c8 0x104cf4000 + 75446472
28 MemoryProvider.iOS 0x00000001056d34a0 0x104cf4000 + 10351776
29 MemoryProvider.iOS 0x000000010a234f30 0x104cf4000 + 89394992
30 MemoryProvider.iOS 0x000000010a2ef5c4 0x104cf4000 + 90158532
31 MemoryProvider.iOS 0x000000010a2f2e04 0x104cf4000 + 90172932
32 MemoryProvider.iOS 0x0000000104dd5ce4 0x104cf4000 + 924900
33 MemoryProvider.iOS 0x0000000104e11d28 0x104cf4000 + 1170728
34 GLKit 0x00000001b3349b20 0x1b332c000 + 121632
35 MemoryProvider.iOS 0x0000000106713680 0x104cf4000 + 27391616
36 MemoryProvider.iOS 0x0000000105cb5f90 0x104cf4000 + 16523152
37 MemoryProvider.iOS 0x00000001094a9bf0 0x104cf4000 + 75193328
38 MemoryProvider.iOS 0x00000001061d8824 0x104cf4000 + 21907492
39 MemoryProvider.iOS 0x00000001056d34a0 0x104cf4000 + 10351776
40 MemoryProvider.iOS 0x000000010a234f30 0x104cf4000 + 89394992
41 MemoryProvider.iOS 0x000000010a2ef5c4 0x104cf4000 + 90158532
42 MemoryProvider.iOS 0x000000010a2f2e04 0x104cf4000 + 90172932
43 MemoryProvider.iOS 0x0000000104dc0374 0x104cf4000 + 836468
44 MemoryProvider.iOS 0x0000000104dc5088 0x104cf4000 + 856200
45 Foundation 0x00000001840cdee8 0x183f69000 + 1461992
46 CoreFoundation 0x0000000182d1a8a8 0x182c80000 + 633000
47 CoreFoundation 0x0000000182d1a7a8 0x182c80000 + 632744
48 CoreFoundation 0x0000000182d19afc 0x182c80000 + 629500
49 CoreFoundation 0x0000000182d14018 0x182c80000 + 606232
50 CoreFoundation 0x0000000182d137d0 0x182c80000 + 604112
51 GraphicsServices 0x0000000199455570 0x199452000 + 13680
52 UIKitCore 0x00000001856402d0 0x184b10000 + 11731664
53 UIKitCore 0x000000018564584c 0x184b10000 + 11753548
54 MemoryProvider.iOS 0x00000001068bea68 0x104cf4000 + 29141608
55 MemoryProvider.iOS 0x0000000105fc5140 0x104cf4000 + 19730752
56 MemoryProvider.iOS 0x0000000105fc4fc4 0x104cf4000 + 19730372
57 MemoryProvider.iOS 0x0000000104e2ecc0 0x104cf4000 + 1289408
58 MemoryProvider.iOS 0x00000001056d34a0 0x104cf4000 + 10351776
59 MemoryProvider.iOS 0x000000010a234f30 0x104cf4000 + 89394992
60 MemoryProvider.iOS 0x000000010a2ef5c4 0x104cf4000 + 90158532
61 MemoryProvider.iOS 0x000000010a2f5878 0x104cf4000 + 90183800
62 MemoryProvider.iOS 0x000000010a213488 0x104cf4000 + 89257096
63 MemoryProvider.iOS 0x000000010a3fb8d0 0x104cf4000 + 91257040
64 MemoryProvider.iOS 0x0000000104e2ebc8 0x104cf4000 + 1289160
65 libdyld.dylib 0x00000001829f2140 0x1829f1000 + 4416
Thread 0 crashed with ARM Thread State (64-bit):
x0: 0x0000000000000000 x1: 0x0000000000000003 x2: 0x00000000000000b4 x3: 0x00000000000010bc
x4: 0x000000000000aa07 x5: 0x0000000000000000 x6: 0x0000000000000000 x7: 0x0000000000000000
x8: 0x00000000fffffbbf x9: 0x0000000000000000 x10: 0x0000000000000010 x11: 0x0000000000000000
x12: 0x0000000000001000 x13: 0x0000000000000000 x14: 0x0000000000000000 x15: 0x0000000000000048
x16: 0xffffffffffffffe1 x17: 0x00000001bd81df1c x18: 0x0000000000000000 x19: 0x0000000000000000
x20: 0x0000000000000000 x21: 0x000000000000aa07 x22: 0x00000000000010bc x23: 0x000000016b1058a8
x24: 0x0000000000000003 x25: 0x00000000000000b4 x26: 0x0000000000000003 x27: 0x00000001d5327f98
x28: 0x000000016b105828 fp: 0x000000016b105880 lr: 0x00000001aebdcd0c
sp: 0x000000016b105830 pc: 0x00000001aebdd908 cpsr: 0x80000000
esr: 0x56000080 Address size fault
From console logs kernel fault messages:
IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 59429 likely leaking IOGPUResource (count=55000)
IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 59429 likely leaking IOGPUResource (count=56000)
IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 59429 likely leaking IOGPUResource (count=60000)
count=60000 is the last one recorded.
If you set UseGPU=false for MapControl before it is created and test it again, the crash happens too?
Do we have a memory problem? You create at each drawing process hundreds of Polygons. They are never reused. Perhaps a dictionary would be helpful to store the already created Polygons? I don't know, if SkiaSharp interface stores some pointers to such structures.
In moment we refresh the MapControl each time we get a new position for the map, because this generates a refresh. Now think about what could happen when you move around the map. We get in the range of sub ms new refresh's. Each of them generates a new bunch of Polygons, only to through them away a few microseconds later.
In moment we refresh the MapControl each time we get a new position for the map, because this generates a refresh. Now think about what could happen when you move around the map. We get in the range of sub ms new refresh's. Each of them generates a new bunch of Polygons, only to through them away a few microseconds later.
This is inefficient wrt performance but if there is no memory leak this should not crash the app.
Perhaps we add some more logging of thing related to memory use. Perhaps:
Logger.Log(LogLevel.Debug, $"Memory after rasterizing layer {GC.GetTotalMemory(true):N0}");
And there may be a way to request memory or feature use in SkiaSharp.
If you set UseGPU=false for MapControl before it is created and test it again, the crash happens too?
With UseGPU = false the crash does not occur. So it seems to be related to drawing a lot of graphics on SKGLView (GPU) and not with SKCanvasView (CPU). This SkiaSharp issue is quite related https://github.com/mono/SkiaSharp/issues/1683
I tried to get some more informations, but didn't find anything except the issue of SkiaSharp you mentioned.
I assume, that this is a problem with the deprecated OpenGL on iOS. Perhaps we have to wait until SkiaSharp uses Metal as backend (perhaps in 2.88.x?). Until than, setting UseGPU=false
on iOS should do the trick. But I don't have an idea about the performance loose.
Maybe we can force UseGPU=false when building for iOS (so people don't have to know about the UseGPU flag when building for iOS).
#if __IOS__
UseGPU=false
#endif
About performance: in my case I didn't notice any performance loss when using UseGPU = false
BTW did you test the same with the Mac version of Mapsui.Forms?
BTW did you test the same with the Mac version of Mapsui.Forms?
No, so far only on IPhone
I don't know, how much this reduces the performance and reaction on iOS. The smartphone's runtime could also be affected.
So it would be better, if this isn't a default change.
This reply indicates that just drawing will eventually crash the app. I'd say we should always worse performance over crash. Also it will most users will be unaware of it and find out late after te release of their app. So often it will not be their conscious choice.
@Sebastian1989101 Are you using GPU on iOS? Encountered such a problem?
A Minimal, Reproducible Example might helpt to get this resolved. This sample could be without Mapsui.
Checks had to be:
- Do you get it with MapControl too?
- Do you get it with the native iOS MapControl too?
- Could you reproduce the problem with a SKGLView without Mapsui?
Why?
- If it is a problem with MapView, then it could be a problem if removing/adding the layers
- If it is a problem with the MapControl of Forms, then it could be a problem with the Forms components of SkiaSharp
- The same as 2.
@Sebastian1989101 Are you using GPU on iOS? Encountered such a problem?
@pauldendulk if UseGPU = true
was always the default in Mapsui 2.0, then it was also set this way in my apps on iOS. But now, I did not encounter this bug yet even with ~13000 data points on the map seperated in ~150 layers. I only had lags when changing the layer collection but nothing else and I tested my apps on multiple devices before each release (iPhone 4S on iOS 9.0 as the oldest). However I just checked the logs for that specific app and there are 67 crashes with a pretty similar crash log to this one with ~52000 daily active users average over the last 30 days, that does not seems to be that impactful. But maybe I also trigger to few redraws from changes.
@Sebastian1989101 Okay thanks. That means it is not as serious as I feared. It could also depend on the kind of feature that is drawn. Bert's sample uses geometries, perhaps you use mainly points.
@pauldendulk yes, most of my thinks are points. Only a few LineString's are used. However I can recreate the issue from the linked SkiaSharp issue with the memory. If I set UseGPU = false
the app uses less memory and more consistant compared to UseGPU = true
. I can't say much about the performance for the latest release tho because I still use my local modified version currently (because without the mass edits of the LayerCollection the loading is just too long on changes in this app).
If anyone feels like it we could create a minimal reproducible sample and post it in skiasharp.
GPU does not work on all platforms. We tried to set sensible defaults (selecting individual platforms). If not the user can override it with MapControl.UseGPU = false;