Select to view content in your preferred language

Reacting to didReceiveMemoryWarningNotification

281
6
10-03-2024 12:12 AM
sveinhal
Occasional Contributor

We have an app with fifty-some layers, a combination of raster tiles, vector tiles and features. On older iPads with 3GB RAM, it is very easy to reach the threshold where iOS kills the app, around 1.8 GB simply by panning around and interacting with the map.

I've found that when receiving didReceiveMemoryWarningNotification from iOS, if we simply do this:

let layers = self.map.operationalLayers
self.map.removeAllOperationalLayers()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  self.map.addOperationalLayers(layers)
}

 

The app releases several hundred megabytes of memory at little noticeable problems for the user.

Not sure how ArcGIS handles internal caching and memory storage, but I think that the library should respect the notification and do its best to clean up unneeded resources. Although the above works for us, I suspect that Esri is in a position to more targeted clear the appropriate memory and provide better user experience.

Also, I'd love for there to be an explicitly callable API to flush caches.

6 Replies
Nicholas-Furness
Esri Regular Contributor

Hi @sveinhal

How we cache internally varies by layer type, and I agree is quite opaque. It's something that's been on our backlog to improve for some time, and internally we're considering how we can deliver a better experience. Posts like this really help us to prioritize that, so thank you.

In terms of us responding to system memory pressure notifications, a better solution would probably be via an API like the one you suggest, so that you as a developer can flush the cache when you receive the notification; for many developers, having data simply disappear from their map without their say-so can be a showstopper.

That said, I'm glad you've identified a solution that can tide you over until we can deliver something more refined.

We have made some improvements in the past. For example, we used to cache image tiled data in memory but realized that for many platforms this was duplicating OS-level HTTP cached data. That did make a good difference to the memory footprint for a lot of people, but there is definitely more that we can do across many layer types.

Just to set expectations: this is probably not something we'd deliver in the next release or two. But it is something we're very interested in improving and is high on our list of priorities.

sveinhal
Occasional Contributor

Are there anything else we can do to reduce memory usage? Is it possible to control some aspects of how the maps are rendered or whatever, that might impact memory usage?

We "own" some of the layers ourselves, and could perceivably do things on our side to optimize memory usage in the client, if there are any tricks we could exploit. Would you e.g. suggest that we pre-render several raster layers into a single layer so that the MapView would handle fewer stacked tiles? Could the choice of raster image file format impact performance? If so, which file format is preferable? Is it possible to tweak the renderer into using scaling tricks? Is raster tiles preferable to vector tiles, or vice versa?

We are willing to trade CPU cycles for memory footprint.

0 Kudos
sveinhal
Occasional Contributor

I've found that if I reduce the frame size of the MapView (geometry reader + explicit frame) and apply a SwiftUI .scaleEffect to the view, I'm effectively using an old game engine trick of rendering at a lower resolution and scaling up.

This works and drastically reduces the memory footprint at a cost of lower resolution of the map, and a somewhat awkward up-scaling of symbols. However, applying a fairly non-aggressive down/up-scale of sqrt(2) seems to keep our app away from the memory pressure landscape and still giving our users a full screen map with a somewhat "normal" feel.

I'd love for a way to influence the renderer directly without this trick, so that e.g. the user location display dot, symbols and callouts don't need awkward tricks to counter the render scale change.

sveinhal
Occasional Contributor

Mention @Nicholas-Furness 

0 Kudos
KristofferS
Emerging Contributor

@Nicholas-Furness @sveinhal This can be reproduced if you add, say, 50 ArcGISTiledLayers to your map. By zooming and panning a little, the map should easily blast through the 1.8GB limit that seem to trigger mem warn on 3GB devices. Now, by doing the "refresh" Sveinhal suggests above, the map memory footprint will drop to a few hundred MBs, and the app survives (for a while)

KristofferS
Emerging Contributor

Created a little video where one of the examples has been tuned to include an (unrealistic) amount of layers and show the effect of "reload operational layers" on memory pressure. 

0 Kudos