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

5658
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
19 Replies
by Anonymous User
Not applicable
Original User: tjmorgan0

I just upgraded from SDK 2.2.1 to 10.1.1 update 1. After working though the changes, I got my app to work on the simulator. Tried testing it on a physical iPad 2 with iOS 6.1.3 and it started crashing. I traced the problem to excessive memory usage and then found this thread. Before the upgrade my app used around 15 MB of memory. Now it tries to use about 80 MB. The usage drops to 40 MB when I don't load the one graphics layer and back to 15 MB when I skip loading the base layer.

Base Layer Code:
     tiledLyr = [[AGSBingMapLayer alloc] initWithAppID:DVCBingMapBasicKey style:AGSBingMapLayerStyleAerialWithLabels];
     tiledLyr.delegate = self;
     [tiledLyr renderNativeResolution];
     [self.mapView addMapLayer:tiledLyr withName:@"Tiled Layer"];

My test graphics layer has 12 AGSSimpleMarkerSymbols with a one attribute each using a AGSUniqueValueRenderer.

Based on my previous experience with Core Data memory bloat, it's best to keep the app below 30 MB. Any ideas other than staying with the old SDK?
0 Kudos
ThaneMorgan
New Contributor
Just tried 10.1.1 update 2. Still crashes for using to much memory. Does anyone have any solution?
0 Kudos
by Anonymous User
Not applicable
Original User: technobrat

Thane,

I'm surprised your app is running out of memory with so few graphics. That is most unexpected.
Can you upload your project so that we can take a look?

Also, can you try v10.2 to see if things are better?

Thanks.
0 Kudos
ThaneMorgan
New Contributor
I'll try 10.2 and get back to you.
0 Kudos
ThaneMorgan
New Contributor
V10.2 uses even more memory than V10.1.1 update 2. My app uses core data and has 10 MB allocated before the maps start to load. When the map loads memory allocation goes over 50 MB. How do you want the app uploaded?
0 Kudos
by Anonymous User
Not applicable
Original User: technobrat

You can zip up the project and attach it to your reply, or put it on dropbox etc.
It'll be helpful if you can reduce the code to the bare minimum.
0 Kudos
ThaneMorgan
New Contributor
I've created a git repository you to which you can connect with Xcode. SignInventory@gsr01.morganconsulting.co:/source/SignInventory.git The branch you want is ESRISDK.

If you will run the command "ssh-keygen" using the terminal on your Mac it will generate "~/.ssh/id_rsa.pub". Email it to me so I can add it to the Git server and give you access to the remote repository.
0 Kudos
by Anonymous User
Not applicable
Original User: technobrat

What's your email?
0 Kudos
ThaneMorgan
New Contributor
0 Kudos
by Anonymous User
Not applicable
Original User: tjmorgan0

Any updates? I'd like to get the new functionality deployed for my app but can't proceed until I have a resolution on this issue.
0 Kudos