iOS 优化地图内存释放相关记录(MKMapView、BKMapView)

地图在应用中占用内存是相对较大的一个模块
我们公司因为核心是做轨迹地图和运动数据的分析处理
涉及到多个地图(百度、高德、Apple、Google)各地图间的兼容和转换处理这里就不一一说了 后面单独写篇文章来记录多地图模块的东西
百度/高德地图内存现在版本来说相对会小一些 因为内存做了图层缓存优化处理
Apple原生地图 用过的同学可能会有一些感觉 渲染绘图优美、响应加载绘制快 带来的问题是内存暴涨 因为苹果地图在滑动区域的时候会缓存图层并不释放 导致增长迅速 400+M都有可能(滑动地图持续内存增长)
如果要优化 要么自己释放内存 (据说苹果在内存吃紧时会释放一些地图的资源)

要么在地图不需要显示的时候销毁释放:
1、地图功能界面不显示是停止绘制操作 清空地图上的加载 保存记录清理前的状态 下次进来时再初始化还原
2、在didReceiveMemoryWarning被调用或监测内存警告的通知时 remove掉地图上的元素、对象和地图本身 下次再进入使用时再初始化;状态也是可以记录下来以便下次还原,做到无缝衔接。
具体机制要根据不同的业务需求来做,这里就不赘述了 有问题有好的方式的同学可以留言讨论

苹果地图释放内存

  • applyMapViewMemoryRelease是 stackoverflow上看到的方法 猜测原理应该就是转化地图类型后苹果地图会释放缓存的图层 做一部分内存释放 原理原则上不推荐这种方式 如果你觉得无伤大雅 可以接受 可以试试 大概会有1/3的内存减少(也会解决滑动越多内存越大的问题)
    据说,假如已退出地图界面,如果app收到内存警告,iOS会把MKMapView占用的内存部分回收, 可以达到50%以上。
//在退出地图的时候可以销毁地图上的所有元素 下次需要再初始化
- (void)destroyMapView
{
    _mapView.mapType = MKMapTypeStandard;
    _mapView.showsUserLocation = NO;
    [_mapView.layer removeAllAnimations];
    [_mapView removeAnnotations:_mapView.annotations];
    [_mapView removeOverlays:_mapView.overlays];
    _mapView.delegate = nil;
    [_mapView removeFromSuperview];
    _mapView = nil;
    [self removeFromSuperview];
}

//在map拖动处理时转换一下地图类型type 能有效释放缓存图层造成的内存暴涨 这不是一个很好的办法 滑动显示区域时会有闪烁
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
     [self applyMapViewMemoryRelease];
}

- (void)applyMapViewMemoryRelease{
    
    MKMapType _type = _mapView.mapType;
    
    switch (_mapView.mapType) {
        case MKMapTypeHybrid:
        {
            _mapView.mapType = MKMapTypeStandard;
        }
            
            break;
        case MKMapTypeStandard:
        {
            _mapView.mapType = MKMapTypeHybrid;
        }
            
            break;
        default:
            break;
    }
    _mapView.mapType = _type;
}

至于网上千篇一律说的这种方式我觉得最好还是别这样写
在滑动时会有闪烁的情况 然后重新加载图层 频繁使用不是很好(上面的方法也是 不建议放在代理中频繁使用)

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    [self.mapView removeFromSuperview];
    [self addSubview:mapView];
}

点数量的限制

经测试发现 地图上绘制线、点的个数不能超过10w 超过2万多就会有明显的卡顿 10w就会因为内存原因crash
所以一般绘制多点的时候需要做限制或者做采样
地图上加载路线的数量、纹理、渐变图层、annotation animation...都是可以处理的空间

百度地图释放内存

之前有说百度地图内部应该已经做了释放内存的机制处理 我们使用的开发人员应该做的就是遵守他的协定调用viewWillAppear、viewWillDisappear周期来做状态缓存恢复和释放,delegate在不使用的时候一定要置nil
再者就是像上面destroyMapView一样做自己添加一些元素的释放机制处理

/// 地图View的Delegate,此处记得不用的时候需要置nil,否则影响内存的释放
@property (nonatomic, weak) id delegate;

获取APP内存和CPU使用情况

贴上同事写的内存获取内存和CPU消耗情况 内存数值会偏大于Xcode debug memory 可能是包含了虚拟内存和apple系统共用库的内存情况 自行借鉴吧

//内存使用情况
+ (unsigned long)memoryUsage
{
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
    if (kr != KERN_SUCCESS) {
        return -1;
    }
    unsigned long memorySize = info.resident_size >> 20;//10-KB   20-MB
    
//    NSLog(@"内存使用情况 %ld",memorySize);
    return memorySize;
}

//cpu占用百分比
+ (float)cpu_usage
{
    kern_return_t            kr = { 0 };
    task_info_data_t        tinfo = { 0 };
    mach_msg_type_number_t    task_info_count = TASK_INFO_MAX;
    
    kr = task_info( mach_task_self(), TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count );
    if ( KERN_SUCCESS != kr )
        return 0.0f;
    
    task_basic_info_t        basic_info = { 0 };
    thread_array_t            thread_list = { 0 };
    mach_msg_type_number_t    thread_count = { 0 };
    
    thread_info_data_t        thinfo = { 0 };
    thread_basic_info_t        basic_info_th = { 0 };
    
    basic_info = (task_basic_info_t)tinfo;    // get threads in the task
    kr = task_threads( mach_task_self(), &thread_list, &thread_count );
    if ( KERN_SUCCESS != kr )
        return 0.0f;
    long    tot_sec = 0;
    long    tot_usec = 0;
    float    tot_cpu = 0;
    for ( int i = 0; i < thread_count; i++ )
    {
        mach_msg_type_number_t thread_info_count = THREAD_INFO_MAX;
        
        kr = thread_info( thread_list[i], THREAD_BASIC_INFO, (thread_info_t)thinfo, &thread_info_count );
        if ( KERN_SUCCESS != kr )
            return 0.0f;
        
        basic_info_th = (thread_basic_info_t)thinfo;
        if ( 0 == (basic_info_th->flags & TH_FLAGS_IDLE) )
        {
            tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
            tot_usec = tot_usec + basic_info_th->system_time.microseconds + basic_info_th->system_time.microseconds;
            tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE;
        }
    }
    
    kr = vm_deallocate( mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t) );
    if ( KERN_SUCCESS != kr )
        return 0.0f;
//    NSLog(@"cpu占用百分比 %f",tot_cpu * 100.);
    return tot_cpu * 100.; // CPU 占用百分比
    
}

暂时先更新到这吧 我比较懒 后面有时间再更新哈 其实做了很多事情 大部分是针对我们地图模块内部业务功能的优化 有童鞋也在做这方面的东西可以留言交流想法 或者有什么好的方案可以分享一下~

你可能感兴趣的:(iOS 优化地图内存释放相关记录(MKMapView、BKMapView))