iOS6 MKMapView 对内存的占用非常高,甚至会导致应用程序崩溃,是否有其他人也注意到了这一点?

52

有没有其他使用iOS 6地图的人在使用其应用程序时注意到极高的内存使用,以至于不停地接收内存警告,直到应用程序崩溃?

我已经通过工具运行了该应用程序,并没有发现任何泄漏,直到创建地图视图时,该应用程序始终以约3mb Live Bytes运行。一旦创建地图并下载图块,Live Bytes就会跳至约13mb Live Bytes。然后,当我移动地图并缩放时,Live Bytes继续上升,直到应用程序在约40mb Live Bytes处崩溃。顺便说一下,这是在iPhone 4上进行的。在iPod touch上,它甚至更早地崩溃。

我正确重用注释视图,没有泄漏。是否还有其他人看到了新的iOS 6地图的同样高内存使用?还有,有人有解决方案吗?


我创建了一个最小的测试应用程序,仅在其中拖放了一个MKMapView,并且在其上看到50-90MB Live Bytes(iPhone 5模拟器)。其他硬件模拟也具有类似高的Live Bytes。因此,这肯定是库的问题。http://stackoverflow.com/questions/13340999/guide-to-acceptable-live-bytes-of-ios6-app-using-mkmapview - Bryce Thomas
12个回答

23

经过很多尝试和测试不同的想法,其中一些在这里被提到,最终对我有用的解决方案如下。

  • 不是按需创建新的 MKMapView,而是将 mkMapView 属性添加到我的 AppDelegate 中,并仅在需要时创建它。一旦创建了它,它就永远存在于 AppDelegate 中,并且我可以在需要时重复使用单个实例。这真的有助于减少内存使用量,因为我之前实例化了几个不同的 MKMapView,而两者都非常快地消耗内存。

  • 我还发现,一旦收到内存警告,iOS 6 Maps 处理释放内存得很好。是的,在缩放和平移时会使用更多的内存,但似乎对内存警告做出了适当的响应。

  • 我最后要做的是减小总体的初始内存占用。我注意到我起始点比预期高得多,所以这也导致了与内存相关的崩溃。一旦我将初始占用内存降低,让 MKMapView 在内存警告时处理其内存,并确保我只有一个可在整个应用程序中重用的 MKMapView 实例,一切都运行正常。


1
Casper,我建议你在实际设备上进行性能分析,而不是在模拟器上。这就是为什么你看到1.84GB的内存被分配的原因。在设备上运行将给你一个更准确的表示,你的实际内存消耗是多少,何时会开始看到内存警告,并且在收到内存警告时你的应用程序将如何处理。你提到的热修复最多只是一个hack,只是在内存警告情况下清除tile cache,而MKMapView本身也会执行此操作。如果你没有看到此行为,我需要查看你的源代码来了解原因。 - Jeremy Fox
@Jeremy 当VC1和VC2在同一个导航栈上时,如何共享单个MKMapView,而它们都有一个地图? - Gong Pengjun
@Gong,对我们来说这很简单。因为我们在地图上显示的只是一些代表物业位置的注释,所以我们构建了MapViewController类,以便根据我们的需求更新UI。如果我们需要呈现搜索结果地图,我们将使用一个名为setupMapWithResults:的方法。如果地图已经在导航堆栈中,并且我们需要呈现保存的属性地图,我们只需从AppDelegate中获取地图实例并调用setupMapForSavedProperties:方法即可。这对我们很有效。 - Jeremy Fox
@JeremyFox 是正确的,在设备上进行性能分析将为您提供更准确的实际内存消耗表示。 - Satish
3
我不明白,在viewwilldisappear中你可以将mapview设为nil并释放它。为什么要创建一个永远存在于内存中的单例?当我初始化时,内存跳到了40MB。即使在我释放它时,当我清除它时,它也会减少20MB。但内存占用量仍然存在。剩余的20MB在哪里被占用了?有任何想法吗? - Ankish Jain
显示剩余3条评论

21

我也遇到了这个问题,这让我很烦恼。 根据mateo的帖子来尝试找出一个临时解决方法,这是我想到的:

- (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;
}

我不确定为什么,但是将视图从superview中移除并将其设置为nil的组合确实降低了内存使用率。我在控制器的viewDidDisappear方法中调用此方法。

我尝试过其他一些事情,但效果不显著:

1)在创建mkMapView的alloc init周围创建autoreleasepool

2)将显示区域设置在纬度84经度-30左右,因为我认为北极的矢量信息可能不太密集... 但这并没有帮助;)

这个问题非常严重,会导致我们的应用程序不稳定,并在iOS 6中引发大量内存警告。希望苹果公司能很快发布比我的更好的热修复...

请批评我的热修复方法,并提出更有效的方法来减少丢弃地图时的内存使用。谢谢!


非常有用的发现,谢谢!只是希望它能释放所有的内存。仍然会留下一小部分映射分配的内存。 - stuckj
3
我删除了switch语句,只留下了最后两行代码,似乎很好地清理了内存。 - Matt Becker
7
据我所见,这个修复方案对iOS 7没有帮助。MKMapView会导致相当严重的内存泄漏问题。 - kal21
1
@kal21同意,实际上,对于iOS7+,我看到这会引起相反的问题。已释放的地图不会释放任何内存,而重新初始化它会导致内存飙升。苹果建议我们在appdelegate中重复使用MKMapView,因此这个答案实际上更有害。 - stevebot

7

我遇到了同样的问题。

在缩放和更改位置后,内存从未被释放。

我找到的唯一窍门是在内存警告后更改地图类型。


7
这个问题在iOS 9中仍然存在 - 除非你这样做。
在故事板中设置了地图视图的视图控制器之间的Segue转换会导致崩溃(对我来说)大约在10-15次显示和关闭周期后。
现在看起来修复很简单。添加这个:
override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    mapView.removeFromSuperview()
}

看起来问题已经解决了,可以循环超过20次而没有问题。没有崩溃!!

希望这有所帮助。这是一个令人沮丧的问题,我很高兴它得到了解决。


1
太棒了!虽然这显然指向了苹果的MKMapView实现存在问题,但调用“removeFromSuperview”对我来说绝对解决了这个问题。我有一个数据批准应用程序,在全屏控制器和需要批准的地图列表之间切换 - 在过去,我只能处理7-10张地图,然后由于内存压力而崩溃。现在我可以一直使用下去,分析器证明这个解决方案有效 - RAM使用率保持在40MB左右,而以前每次打开带有地图的VC时,它都会增加约30-40MB,直到崩溃 - 谢谢! - DiscDev

5

这不是一个解决方案,而只是一个技巧...

...改变mapType => mapkit释放内存。

即使这个改变只有一小部分时间。


5
我的足迹是:2.48; 19.51; 49.64; 12.60,分别代表在加载地图视图前、加载后、缩放后以及释放地图视图后的内存占用情况(即使释放了地图视图,仍然会保留10MB的增量,这真的很烦人!)。无论如何,我不再使用 MapView 的 IBOutlet,而是全部在代码中创建。新的足迹现在是:2.48; 19.48; 38.42; 12.54。仍在努力降低内存占用。

我完全能理解你的最后一条评论。 - Gmeister4

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];
}

这在iOs 8.4上可以工作,但在切换地图模式时会出现地图闪烁的问题,这肯定会降低用户体验。 - Juan Boero

3

我有同样的感觉,不知道如何释放这个内存,即使没有使用MKMapView

我已经释放了控制器、MKMapView、容器视图...内存仍然被占用。

我不记得在iOS5中有过旧版MKMapView的类似经历。


2

对于那些在2014年及之后(iOS8及以上版本)使用的设备:

我在iOS 7+上遇到了这个问题,试图支持旧设备(比如仅有512MB内存的iPad 2)。

我的解决方案是禁用缩放功能,因为它很容易占用最多的内存。

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

我已经尝试了所有的方法,从切换地图类型到释放地图、将委托设置为nil、删除所有覆盖层、注释等等。

在iOS7+上,这些方法都不起作用。事实上,大多数修复方法会导致内存跳动,因为MKMapView似乎会泄漏并且无法正确释放(我通过子类化验证过dealloc被调用)。

这很糟糕,但我目前想到的唯一方法是禁用地图功能(缩放、滚动、用户交互),以限制MKMapView占用的内存。这样至少可以使我的应用程序在旧设备上半稳定。


2

我遇到了同样的问题 -

我不是很确定,但是这可能是因为新的苹果地图预加载了大量地图区域以满足离线导航需求?

如果你在地图加载完后关闭连接,然后尝试放大到完全不相关的区域,则似乎仍然有很多细节信息可用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接