I'm developing an enterprise map-based application and it needs to display info gathered from a large workforce and display it all on each worker's iPad. So the number of markers on the map can grow very very large (several thousands) quickly. In addition, each marker is going to be backed by an NSManagedObject subclass that's held in memory while the marker exists.
I'm using Google Maps iOS SDK, and the problem is, even without any markers, just panning and zooming around causes really large increases in memory usage. The application's dirty memory size is 100MB (using Allocations tool) upon launch. Little bit of panning and zooming quickly makes it shoot to up to 300, and the issue is when I stop panning and zooming, the memory never goes down. Similarly if I have a lot of markers on and I remove them, again, no drop in memory (when I remove markers, I make sure to not hold any references to any of the objects too). The only time memory goes down is when I change map types. If I pan/zoom a lot in street view, then switch to satellite view, there's a sudden 50MB+ drop in dirty memory.
So I was wondering if anyone has any tips in handling memory when using Google Maps, or any info on how Google Maps manages/releases memory?
Related
I have an iOS 8 app that uses MapKit. I recently discovered a performance problem with the app when running a video decompression in addition to displaying a map. The app was unable to keep up with the flow of incoming data when using the satellite view tile set. However, this problem vanished the moment I swapped to the default MapKit tile set. The app is not CPU bottlenecked when the problem is occurring. It makes sense to me that the default (vector) map tile set is easier to display, but I am confused about why the issue is happening in the first place.
The problem seems strange to me because there is no movement or manipulation of the map when the problem is occurring. I would understand the issue better if it happened when manipulating the map in addition to rendering video to the screen, but the problem exists even with no user input. I am constrained in analyzing the system because we use a hardware accessory, so some Instruments are not available over wireless performance analysis. I am not using a high number of annotations, overlays, or other objects. We have a few custom annotations and overlays in use. There are existing apps that do this exact combination of decoding and maps, without the performance problem, so I suspect it's a configuration issue.
Are there certain attributes on the MKMapView that I can set to improve performance? I am at a loss as to what to investigate further since I cannot make the problem happen with the GPU Instrument active and the CPU doesn't appear to be the constraint.
My project runs at 55-60FPS on an iPhone 6 but anything older is completely unplayable because something is eating CPU.
I think the issue is related to the number of tiles and layers on my map (64x256 with 4 layers) and Instruments shows "SKCRenderer:preprocessSpriteImp(..." taking 5198ms (23.2%) running time.
Does JSTileMap load every single tile's image (visible or not) at once? This post from RW indicates that is the case and that it could be worked around for large performance boosts:
http://www.raywenderlich.com/forums/viewtopic.php?f=29&t=9479
In another performance note - Sprite Kit checks all it's nodes and
decides which ones it needs to display each frame. If you have a big
tile map, this can be a big performance hit. JSTileMap loads all the
nodes (SKSpriteNode for each tile) when it loads the tile map. So, I
was also seeing performance issues in the Sprite Kit version with my
maps (which are 500 x 40 tiles). I added a check to my version of
JSTileMap that's included in the kit that marks the hidden property of
each tile, then intelligently unhides and hides only the tiles that
enter/exit the screen space. That increased performance on these
larger maps significantly.
Unfortunately that post does not go into detail regarding the steps taken to remedy this.
My first thought was to (I'm a beginner, please be gentle) create an array of nodes by looping through each point and checking for a tile on the specific layer. From there I'd work on adding/removing them based on distance from the player.
This didn't work, because the process of adding nodes to an array simply caused the app to hang forever on larger maps.
Could someone lend a hand? I'd love to work with larger/more complicated tilemaps but this performance issue is destroying my brain.
Thanks for reading!
UPDATE: Big thanks to SKAToolKit: https://github.com/SpriteKitAlliance/SKAToolKit
Their culling feature solved my problem and I'm now running even larger maps at less than 35% CPU.
JSTileMap has some issues handling larger maps but you do have a couple of options to consider:
Break your large map into several smaller pieces and load each new piece as required.
Only load those objects which are in the player's vicinity.
Only load those tiles which are in the player's vicinity.
I personally found it impossible to accomplish #3 with JSTileMap as I could not locate an array holding the map tiles. I solved this issue by using the SKAToolKit which provides easy access to map tile arrays. It is an excellent resource for parsing maps created in Tiled.
I am developing an iPad paint application.In my application there is a sketch book on which the user can draw sketches in any page.I have done drawing sketches by identifying user touches.In the application,I am detecting swipe gesture (up/down) and turn pages one by one using curl page transition animation & I have successfully implemented it.
Now the problems are:
1.There comes a conflict between my drawing and turning pages as both of them are analyzing user finger touches.(For eg: When I draw with a pen from bottom to top,the swipe gesture detects the swipe event and immediately turns the page.Similarly when I try to swipe a page,sometimes the app draws a stroke on that portion).I would like both of them work at the same time.Is there any way?
2.A user can create N number of drawing in the application.And currently what I have done is,to save current drawing once the user turns the page or tries to navigate away from the screen(in order to use minimum memory).When the next/previous page is about to load,the app will get the proper image from cache directory and loads it.(Previously I kept each of these drawings in an array by fetching every drawings from cache directory.).I am maintaining a database to store the IDs of each drawing and uses this id to read the image from cache directory.The problem is that,After using a couple of minutes(say 5 or 10) the app still throws memory warning.Is there anyway to avoid that?
I have tried to compress images to resolve memory warnings,but the compression makes the images somewhat weird.I am using https://github.com/acerbetti/ACEDrawingView for normal paint strokes and there is another paint tool that uses OpenGL for specific type of stroke.
I think without code it will difficult to predict where the memory leak is . The best option is to profile your application. Go to product -> Profile (window + I). Now you can see which of the variable taking the memory .
Note : if you are using ARC then garbage collector will take care of releasing the memory .
If you are allocating the some memory using malloc or calloc its your responsibility to release that memory .
I'm working on an iPad-only iOS app that essentially downloads large, high quality images (JPEG) from Dropbox and shows the selected image in a UIScrollView and UIImageView, allowing the user to zoom and pan the image.
The app is mainly used for showing the images to potential clients who are interested in buying them as framed prints. The way it works is that the image is first shown, zoomed and panned to show the potential client if they like the image. If they do like it, they can decide if they want to crop a specific area (while keeping to specific aspect ratios/sizes) and the final image (cropped or not) is then sent as an email attachment to production.
The problem I've been facing for a while now, is that even though the app will only be running on new iPads (ie. more memory etc.), I'm unable to find a method of handling the images so that the app doesn't get a memory warning and then crash.
Most of the images are sized 4256x2832, which brings the memory usage to at least 40MB per image. While I'm only displaying one image at a time, image cropping (which is the main memory/crash problem at the moment) is creating a new cropped image, which in turn momentarily bumps the apps total RAM usage to about 120MB, causing a crash.
So in short: I'm looking for a way to manage very large images, have the ability to crop them and after cropping still have enough memory to send them as email attachments.
I've been thinking about implementing a singleton image manager, which all the views would use and it would only contain one big image at a time, but I'm not sure if that's the right way to go, or even if it'd help in any way.
One way to deal with this is to tile the image. You can save the large decompressed image to "disk" as a series of tiles, and as the user pans around pull out only the tiles you need to actually display. You only ever need 1 tile in memory at a time because you draw it to the screen, then throw it out and load the next tile. (You'll probably want to cache the visible tiles in memory, but that's an implementation detail. Even having the whole image as tiles may relieve memory pressure as you don't need one large contiguous block.) This is how applications like Photoshop deal with this situation.
I ended up sort of solving the problem. Since I couldn't resize the original files in Dropbox (the client has their reasons), I went ahead and used BOSImageResizeOperation, which is essentially just a fast, thread-safe library for quickly resizing images.
Using this library, I noticed that images that previously took 40-60MB of memory per image, now only seemed to take roughly half that. Additionally, the resizing is so quick that the original image gets released from memory so fast, that iOS doesn't execute a memory warning.
With this, I've gotten further with the app and I appreciate all the idea, suggestions and comments. I'm hoping this will get the app done and I can get as far away from large image handling as possible, heh.
Is it better in terms of memory management, battery life and processor usage to remove currently not visible MKAnnotations from MKMapView or not?
I'm talking about BIG amounts of annotations (say ~1000) with only about 20 visible in current region at any given time. Should I let MapKit do his job with hiding of pins or should I handle adding/removing of annotations depending on visible region myself?
The annotations that are offscreen will not cause a large memory usage. MKAnnotation is designed to be very lightweight and you should try to keep them small. The memory hog is the associated view (the MKAnnotationView). If you have more than a few hundred visible it will cause a slowdown and large memory use with a possible crash on older devices. 1000 will slow down any device but probably won't crash it.
To sum up, the offscreen annotations don't matter. The problems arise when you have too many onscreen. For that you have to remove annotations to get better performance. How you decide to remove and replace annotations is a much more difficult question.
I'd make sure to show not more than 100 annotations simultaneously. When you let MKMapView handle it, how do you prevent the user from zooming out to the whole world causing mapView to display all your 1000 annotations?