iOS6 MKMapView using a ton of memory, to the point of crashing the app, anyone else notice this?
Asked Answered
B

12

52

Has anyone else, who's using maps in their iOS 6 apps, noticing extremely high memory use to the point of receiving memory warnings over and over to the point of crashing the app?

I've ran the app through instruments and I'm not seeing any leaks and until the map view is created the app consistently runs at around ~3mb Live Bytes. Once the map is created and the tiles are downloaded the Live Bytes jumps up to ~13mb Live Bytes. Then as I move the map around and zoom in and out the Live Bytes continuos to climb until the app crashes at around ~40mb Live Bytes. This is on an iPhone 4 by the way. On an iPod touch it crashes even earlier.

I am reusing annotation views properly and nothing is leaking. Is anyone else seeing this same high memory usage with the new iOS 6 maps? Also, does anyone have a solution?

Brackett answered 28/9, 2012 at 14:9 Comment(1)
I created a minimal test app with nothing more than an MKMapView drag n' dropped on it and see on the order of 50-90MB Live Bytes (iPhone 5 simulator). Similarly high Live Bytes with other hardware simulated. So it would certainly seem this is an issue with the library. #13341499Hypoderma
B
23

After a lot of playing around and testing different ideas, some of which were mentioned here, the final solution that worked for me was as follows.

  • Instead of creating new MKMapView's as needed in the app, I added an mkMapView property to my AppDelegate and only created it when needed. Once it has been created, it lives in the AppDelegate forever and I reuse that single instance everywhere needed. This really helped in reducing the amount of memory being used as I was previously instantiating a couple different MKMapView's and both were burning through memory pretty quickly.

  • I also found that iOS 6 Maps handles releasing memory very well once a Memory Warning has been received. Yes, it does use up more memory while zooming and panning, but seems to be responding to Memory Warnings appropriately.

  • The last thing I had to do was work on reducing my overall initial memory footprint. I noticed I was starting off way higher than I expected so that was also contributing to the crashes I was receiving related to memory. Once I got the initial footprint down, let MKMapView handle releasing it's memory during Memory Warnings, and made sure I only had 1 instance of MKMapView that I could reuse throughout the app, everything is running fine.

Brackett answered 7/1, 2013 at 14:42 Comment(8)
If I have my MKMapView setup in a storyboard as one of the screens of a UITabBarController how would you go about placing it into AppDelegate? Is there a way to do it still using storyboard, or does one have to remove it from there and then add it programmatically? So with alloc, setting its frame, etc. ?Declarative
Casper, if you only have one MKMapView in your app and you allow it to live forever in its one location it should make a difference whether you have it in a view controller or the app delegate. Just don't create multiple instances of MKMapView and you should be good. Are you seeing memory issue with your one map?Brackett
After some zooming, pinching, etc in the iPad simulator my allocations totaled 1.84 GB (!) After implementing the hot-fix (switching of mapType in - (void)didReceiveMemoryWarning) it never went past 200 MB.Declarative
Casper, I would suggest profiling on an actual device, not the simulator. This is the reason you are seeing 1.84GB's of memory being allocated. Running on a device will give you a far more accurate representation of what your actual memory consumption is, when you will start seeing memory warnings, and what your app will do when it receives them. The hot fix you are referring to is a hack at best and is only doing what MKMapView will do by itself in the even of a memory warning, clearing the tile cache. If you are not seeing this behavior, I'd have to look at your source code to see why.Brackett
@Jeremy How to share single MKMapView when VC1 and VC2 both have a map while they are on the same navigation stack?Raindrop
@Gong, for us it was pretty simple. Since all we are ever showing on the map are some annotations representing property locations, we constructed our MapViewController class to be able to update the UI based on what we needed. If we needed to present the search results map, we would use a method named something like setupMapWithResults:. If the map was already in the nav stack and we needed to present a saved properties map we simply grabbed the map instance from the AppDelegate and called the setupMapForSavedProperties: method. This worked well for us.Brackett
@JeremyFox is right, profiling on a device will give you a far more accurate representation of what actual memory consumption is.Giesecke
I dont understand. When in viewwilldisappear you can nil the mapview and deallocate. Why should you make a singleton which lives in the memory forever ? .When i initialize memory jumps to 40 mb. WHen i clear it reduces by 20 mb in my case even when i free it . The memory footprint continues to occupy. Where does rest of 20mb is occupied ? Any idea ?Nightrider
F
21

I'm also having this problem and its driving me nuts. Trying to figure out a hotfix based on mateo's post, this is what I came up with:

- (void)applyMapViewMemoryHotFix{

    switch (self.mkMapView.mapType) {
        case MKMapTypeHybrid:
        {
            self.mkMapView.mapType = MKMapTypeStandard;
        }

            break;
        case MKMapTypeStandard:
        {
            self.mkMapView.mapType = MKMapTypeHybrid;
        }

            break;
        default:
            break;
    }

    [self.mkMapView removeFromSuperview];
    self.mkMapView = nil;
}

Im not sure why, but the combination of removing from superview and then setting to nil really reduces the memory usage. I call this method in the controller's viewDidDisappear.

Other things I tried but without significant effect:

1) Creating autoreleasepool around alloc init of the mkMapView

2) Setting displayed region around lat 84 lon -30 as I thought Vector Information in the Arctic might not be as dense... However, doesnt help ;)

This issue is very serious and causes our app to be unstable and cause tons of memory warnings in iOS 6. Sure hope that Apple releases a better hotfix than mine... soon!!

Please critique my hotfix and come up with more effective methods to cut memory usage when discarding a map. Thanks!

Fedak answered 20/10, 2012 at 7:37 Comment(4)
Super-useful find, thanks! Just wish it free'd up all of the memory. Still leaves a small chunk of the map-allocated memory.Sextet
I removed the switch statement and just left the last two lines and it seems to clean the memory up very well.Infatuate
As far as I see this fix does not help in iOS 7. MKMapView causes pretty severe memory leaks.Submersed
@Submersed agreed, in fact, for iOS7+, I see this causing the opposite problem. The deallocated map doesn't free any memory, and having to reinit it causes memory to skyrocket. Apple recommends that we re-use our MKMapView's in the appdelegate, so this answer is actually more harmful.Bier
C
7

I experience the same issue.

Memory is never released after zoom and change location.

The only trick i've found is to change map type after memory warning.

Cameraman answered 10/10, 2012 at 7:21 Comment(0)
Z
7

This issue is still present in iOS 9 - unless you do this.

Segue to and from a view controller with a map view that has been set up in a story board causes a crash (for me) after about 10-15 show and dismiss cycles.

Now it appears the fix is simple. Adding this

override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    mapView.removeFromSuperview()
}

Seems to have fix the issue, the can cycle to and from more than 20 times, and no issue. No crash!!

Hope this helps. This was a frustrating problem and glad its solved.

Zetta answered 6/9, 2015 at 10:17 Comment(1)
Amazing! While this clearly points to issues with the MKMapView implementation from Apple, calling "removeFromSuperview" definitely fixed this for me. I have a data approval app where I'm flipping between a full-screen controller with a map, and a list of maps to approve - in the past I could only get through 7-10 maps before it would crash due to memory pressure. Now I can go forever, and the profiler proves that this solution worked - RAM usage stays around 40MB, whereas before, it would increase by about 30-40MB every single time I opened the VC with the map on it, until crashing-Thanks!Henninger
S
5

My footprint was: 2.48; 19.51; 49.64; 12.60 which is: Memory before loading the mapView, after loading the mapView, after zooming in/out a bit, and after releasing the mapView (which is quite annoying, even after releasing the mapView, I keep 10MB increment and it doesn't go down!)

Anyway, I am not using an IBOutlet for the MapView anymore, I am creating everything in code instead. The new footprint is now: 2.48; 19.48; 38.42; 12.54.

Still working on putting the bi*** down.

Scissor answered 2/10, 2012 at 1:58 Comment(1)
I can totally relate to your last commentBurn
L
5

Not a solution but simply a trick...

... change mapType => mapkit release memory.

Even if this change is for a fraction of second.

Lye answered 11/10, 2012 at 0:41 Comment(0)
L
3

I've got the same feeling and don't know how to release this memory, even when MKMapView is not used.

I've released controller, MKMapView, container view... memory is still used.

Don't remember to experience this with old MKMapView in iOS5.

Lye answered 3/10, 2012 at 12:59 Comment(0)
M
3
- (void)applyMapViewMemoryHotFix{

    switch (self.mapView.mapType) {
        case MKMapTypeHybrid:
        {
            self.mapView.mapType = MKMapTypeStandard;
        }

            break;
        case MKMapTypeStandard:
        {
            self.mapView.mapType = MKMapTypeHybrid;
        }

            break;
        default:
            break;
    }


    self.mapView.mapType = MKMapTypeStandard;



}
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    [self applyMapViewMemoryHotFix];
}
Myself answered 15/10, 2014 at 22:42 Comment(1)
This works as iOs 8.4, but gives a map flicker while swapping map modes that will surely decrease the UX (user experience).Kory
C
2

I'm receiving same issue -

I'm not entirely sure about this, but could it be that the new apple maps preloads a huge area of the map to cater for offline navigation?

If you turn your connection off after the map has loaded, then try and zoom in on areas nowhere near the desired location then there seems to be an awful lot of detail still available.

Cupping answered 19/11, 2012 at 16:11 Comment(0)
B
2

For those journerying here in 2014+ (iOS8 and up)

I am running into this problem on iOS 7+ trying to support older devices (think Ipad 2 with 512MB).

My solution is to disable Zoom as it easily takes the most memory.

   long mem = [NSProcessInfo processInfo].physicalMemory;
    if(mem < _memory_threshold){
        self.MapView.zoomEnabled = NO;
    }

I have tried everything from switching map types, to deallocating the map, setting the delegate to nil, removing all overlays, annotations etc.

None of that works on iOS7+. In fact, most of these fixes cause jumps in memory, as MKMapView seems to leak and never properly dealloc (I have verified through sub-classing that I see dealloc hit).

This sucks, but all I have came up with so far is disabling map features (zoom, scroll, user interactions) as a means to limit the atrocious amount of memory MKMapView takes. This has resulted in my App at the very least being semi-stable on older devices.

Bier answered 11/11, 2014 at 21:17 Comment(0)
C
1

Not sure about the consequences.

How ever setting map to 'nil' whenever view disappears, helped me to reduce memory usage from ~250MB to ~50-60MB.

-(void)viewDidDisappear:(BOOL)animated
{
     self.map = nil; 
}
Cortes answered 5/11, 2014 at 6:38 Comment(1)
I also adding this line helped to reduce the memory. [self.map removeFromSuperview];Toothpaste
W
-1

Only following lines are enough to resolve the memory issue:

For Objective-C:

- (void) applyMapViewMemoryFix {
  [self.mkMapView removeFromSuperview];
  self.mkMapView = nil;}

For Swift 3.0:

func applyMapViewMemoryFix() {
    mapView.removeFromSuperview()
    self.mapView = nil
}
Whippet answered 26/3, 2018 at 12:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.