Memory bloat, CPU spikes, and UI thread locking with 10.1.1 SDK

5652
19
Jump to solution
01-23-2013 09:52 AM
by Anonymous User
Not applicable
Original User: bernese

I am seeing UI thread locking, very high CPU load spikes, and a much larger memory footprint after upgrading a project from the 2.3 SDK to the new 10.1.1 SDK and making no other changes. Within a test project I created to isolate the issue from my own code, I am seeing identical CPU load spikes, increased but more reasonable memory use, and some brief UI thread locking. Both projects target iOS 5.0 at minimum and are configured in the default manner for an iOS project using the ArcGIS 2.3 or 10.1.1 SDK. I have tested both on all versions of the iPad and with OS versions ranging from 5.0 to 6.0.1.

The use case I am benchmarking with in my production project is the following:
[INDENT]1) User moves finger across map to sketch a query geometry.
2) Query is performed against a dynamic map service layer using AGSQueryTask.
3) About 200 returned features are drawn in a graphics layer as composite symbols consisting of a picture marker symbol (pin) and simple marker symbol (colored dot).
4) User navigates features using either the map or a sorted table view, and can drill down into details/sub views for each feature. In my test case, I always query against a layer of state traffic cameras, so the user is looking at the video feed for a given camera.[/INDENT]


I have attached screen shots of my diagnostics using Instruments and refer to those when appropriate. I have also attached my test project.

In 2.3, the app (item iRaptor in the Instruments screen shots) develops an initial memory footprint of about 20 mb (see 2.3_baseLoad.png). Performing the described query and navigating the result in the table view increases that to around 65-70 mb (see 2.3_afterRendering.png). Removing the graphics layer from the map view and emptying it of graphics drops the memory footprint to around 30 mb. In general, panning/zooming the map or adding and removing a layer seems to generate a slight, persistent increase in the app memory footprint, presumably because of some caching action. CPU usage maxes out around 60-80% when interacting with the map and table view, and although map rendering sometimes takes a second or two to catch up to the user panning/zooming/selecting, no UI locking occurs.

In 10.1.1, the initial app footprint is about 50mb (see 10.1.1_baseLoad.png). Performing the test case query initially increased the footprint to the 350-400 mb range (see 10.1.1_afterRendering4GraphicsLayers). I initially tried troubleshooting this inexplicably high memory footprint, and discovered that adding 4 empty AGSGraphicLayer objects caused an instant memory footprint increase into the 350-400 mb range. This level of memory usage is high enough to trigger numerous first level memory warnings on an iPad 3 while viewing the query results. Adding the empty graphics layers also created a CPU spike into the 160-180% range (most of both cores on an iPad 3), and a complete lockout of the UI that persisted for 2 to 3 seconds.

I pared the 4 graphics layers down to 2; one for displaying the selection the user made and one for displaying returned graphics with any geometry type. Previously, I had a separate graphics layer for each geometry type because the SDK documentation indicates that this is best practice and there was no real cost in maintaining many graphics layers, only in drawing many graphics. With only two graphics layers on the map, the memory spike is down to about 160mb, which is too low to trigger memory warnings but still seems very high for adding two empty graphics layers.

However, getting the memory usage down has not affected CPU spikes into the 140-180% range when panning, tapping on a graphic to display a popover, or selecting a table view item and causing the corresponding graphic to display its popover (see 10.1.1_cpuLoadSpike_production). UI locking occurs during and after these spikes and can persists for 2-3 seconds, making the the map and table view entirely unresponsive. This makes 10.1.1 unusable for my production app. Again, no other changes were made and there were no issues in 2.3.

I created a simple test app using the 10.1.1 SDK that explores rendering performance of different layer types by plotting a single layer from a dynamic map service using either AGSDynamicMapServiceLayer, AGSFeatureLayer, or AGSGraphicsLayer. For the AGSGraphicsLayer, graphics can be rendered with a simple picture marker symbol or a more complex composite marker symbol. Additionally, the CPU and memory usage are displayed in one corner (these calculations match Instruments fairly accurately). Inspecting the test app in Instruments, I see significantly smaller memory bloat, CPU usage spikes of up to 160% when panning/zooming on either the feature or graphics layer, and momentary stuttering/locking of the map during and after these spikes (see 10.1.1_cpuLoadSpike_test). The dynamic layer re-renders with a CPU load of up to 110% and is generally more smooth/responsive. 

I believe that the UI locking issues on my production app are due to the CPU usage spikes during rendering. In my production app and when rendering feature or graphics layers in my test app, I can see that the generated CPU load significantly drives down CPU time given to system processes. If an app is using most of both cores on an iPad 3 when rendering the map, it seems reasonable to assume that, in conjunction with system processes, there are not enough cycles available to maintain a smooth UI, especially when displaying a table or content view alongside the map. My experience with iOS over the past few years/versions is that once a CPU spike of that size occurs and interferes with the UI and other threads, UI lock will persist for a few seconds after the spike has subsided as the system sorts itself out.

I am unsure about the memory bloat in my production app. As noted, I have determined that adding an empty AGSGraphicsLayer to the map has what appears to be an oddly high memory cost. To be clear, the memory cost is incurred when the layer is added to the map, not when it is created.

I benchmarked a few graphics-intensive iPad apps/games that use OpenGL for rendering and did not see CPU usage spikes or CPU usage anywhere near as high as I am seeing with the 10.1.1 SDK, so I don???t think it is anything intrinsic to using OpenGLES for rendering. For instance, InfinityBlade2 did not get over 110% during gameplay and was typically in the 50-60% range.

I noted a similar thread from a few days earlier, but wanted to add my in-depth analysis. I would love to hear of any solutions to the CPU spiking and memory footprint issues that can be implemented with the current SDK. If these issues will persist until an update is released, any sort of timeline on that is greatly appreciated since 10.1.1 contains a number of breaking changes and I would like to be able to balance the lost time of going back to 2.3 against my need to move this production app forward and plan for updating other projects from 2.3.
0 Kudos
1 Solution

Accepted Solutions
by Anonymous User
Not applicable
Original User: technobrat

I was able to reproduce the behavior you described. We're looking into the cause of the issue, but I fear there might not be an easy fix. We may have to make deep rooted changes to our display pipeline to better cope with the large number of pixels on iPad retina devices.

Maybe you can try further reducing the number of graphics layers in your app? You said you used one layer exclusively for showing selected symbols. The graphics layer now has a highlight color and a selection symbol that you can use to either display a halo around the selected graphic, or change it's symbol entirely.

If you want to discuss more options, you can drop me an email at d g o y a l AT e s r i dot c o m

View solution in original post

0 Kudos
19 Replies
DanaMaher
Occasional Contributor
Addendum: The previous thread I was referring to is this one. I downloaded the sample code provided by brendan09. I looked at his bug and I do not think we are experiencing the same issue.

Looking at brendan09's test app in Instruments, I am not seeing the CPU load spikes that seem to be causing my issue. This makes sense since he only adds a tiled layer and my issues relate to feature and graphics layers. Also, his UI lockout only affects the map and is a complete lack of map rendering until table scrolling ends. Touches appear to be interpreted in the interim and the map catches up fairly quickly once the table view scrolling ends. The lockout I experience affects the entire UI and interrupts gesture recognition, resulting in a pronounced stutter/lag.
0 Kudos
by Anonymous User
Not applicable
Original User: technobrat

Hi, Dana -

Thank you for describing the problem so thoroughly and reporting the results of your investigation. Thank you for also providing a simplified testcase. We will look into the issues you're reporting and get back to you soon. In the meanwhile,  I'd be curious to know if you're seeing similar results on other devices (maybe a retina iphone or a non-retina iPad ?), or if the problem is either specific or exaggerated on the iPad 3. The reason I ask is because iPad 3 has a many more pixels (2048 x 1536 = 3.1 million) than other iOS devices.

Also, can you confirm if your simplified testcase will reproduce this behavior -

I have determined that adding an empty AGSGraphicsLayer to the map has what appears to be an oddly high memory cost. To be clear, the memory cost is incurred when the layer is added to the map, not when it is created.
0 Kudos
DanaMaher
Occasional Contributor
Divesh,

Thank you.

No, that test case does not replicate the memory issue. After adding the AGSGraphicsLayer and adding the retrieved graphics to that layer, the test app's memory footprint increases about 25 mb. If you were to prevent the layer from drawing any graphics, you would see that the instantaneous memory increase from just adding the AGSGraphicsLayer is about 20 mb. I quickly hacked apart my original test case to show the cost of simply adding an empty AGSGraphicsLayer to an AGSMapView. Instead of switching between layer types, I just have a slider that sets the map to have between 0 and 20 empty AGSGraphicsLayers. Each empty graphics layer seems to cost about 20 mb, regardless of how many other layers are also on the map.

The memory usage increase I am seeing in my production app is obviously much higher. One thing that has occurred to me is that I am adding a custom drawing UIView on top of the map to allow the user to see in real time the freehand selection they are making. The custom UIView is not added directly onto the AGSMapView, but into the view containing the AGSMapView. This custom UIView  draws a closed polygon in its layer in response to the user moving their finger. This is then converted to an identically symbolized AGSGraphic when the user is done with their gesture, the custom drawing UIView is dismissed, and the map returns to normal functioning. If the memory cost has to do with the map view adding each layer into rendering calculations even if it is empty, perhaps having an overlay over the map is increasing that memory cost.
0 Kudos
DanaMaher
Occasional Contributor


...I'd be curious to know if you're seeing similar results on other devices (maybe a retina iphone or a non-retina iPad ?), or if the problem is either specific or exaggerated on the iPad 3. The reason I ask is because iPad 3 has a many more pixels (2048 x 1536 = 3.1 million) than other iOS devices.



I took another look at the production and test apps on an iPad 2 and an iPad mini. The memory footprint is smaller, but I still get the same level of CPU spiking during render of graphics/feature layers. The attached Instruments log is from running on a mini, but the memory footprint and spiking is almost identical on the 2.
0 Kudos
by Anonymous User
Not applicable
Original User: technobrat

I was able to reproduce the behavior you described. We're looking into the cause of the issue, but I fear there might not be an easy fix. We may have to make deep rooted changes to our display pipeline to better cope with the large number of pixels on iPad retina devices.

Maybe you can try further reducing the number of graphics layers in your app? You said you used one layer exclusively for showing selected symbols. The graphics layer now has a highlight color and a selection symbol that you can use to either display a halo around the selected graphic, or change it's symbol entirely.

If you want to discuss more options, you can drop me an email at d g o y a l AT e s r i dot c o m
0 Kudos
HumzaAkhtar
Occasional Contributor II
I was able to reproduce the behavior you described. We're looking into the cause of the issue, but I fear there might not be an easy fix. We may have to make deep rooted changes to our display pipeline to better cope with the large number of pixels on iPad retina devices.

Maybe you can try further reducing the number of graphics layers in your app? You said you used one layer exclusively for showing selected symbols. The graphics layer now has a highlight color and a selection symbol that you can use to either display a halo around the selected graphic, or change it's symbol entirely.

If you want to discuss more options, you can drop me an email at d g o y a l AT e s r i dot c o m


Hi,

I am having the same issue. I am only using four empty graphic layers at the start of my app and the memory (live bytes) jump upto 40-50 mb right in the beginning of the test. and no matter how much i try to do removelayer or set it to hidden or to nil, the memory doesnot get released.

However the esri arcgis app doesnot suffer from this problem. Any idea anybody why is this so.
0 Kudos
by Anonymous User
Not applicable
Original User: humzarr

Hi,

Should I start a new thread with the same issue because this thread doesnot provide any answer. The esri arcgis ios app doesnot give memory spikes no matter how many layers you add on to it. therefore there must be another work around to this issue not just saying that this is a fault of arcgis is a suitable answer to the question.
0 Kudos
by Anonymous User
Not applicable
Original User: bernese

Hi,

Should I start a new thread with the same issue because this thread doesnot provide any answer. The esri arcgis ios app doesnot give memory spikes no matter how many layers you add on to it. therefore there must be another work around to this issue not just saying that this is a fault of arcgis is a suitable answer to the question.


I can confirm that the behavior I described above *was* occurring in the manner described for the 10.1.1 SDK. This issue rendered one of my production projects unusable with 10.1.1 until it was resolved. From your description above, it is hard to tell whether you are reproducing the conditions. You may not be drawing a large number of graphics, may be running on the simulator, may or may not be using a retina device if you are running on device, etc. Contact Divesh, the ESRI developer who replied to the thread, if you want more information or a potential fix. You may be experiencing a different issue, so it might be good to start a new thread with:

1) A complete, itemized description of your workflow and issue.

and

2) Sample code that reproduces your issue.
0 Kudos
NimeshJarecha
Esri Regular Contributor
ArcGIS Runtime SDK for iOS v10.1.1 Update 1 is available now.

Regards,
Nimesh
0 Kudos