美文网首页iOS DeveloperiOS开发 UI类地图开发相关
iOS 优化地图内存释放相关记录(MKMapView、BKMap

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

作者: iii余光 | 来源:发表于2018-07-02 17:07 被阅读44次

    地图在应用中占用内存是相对较大的一个模块
    我们公司因为核心是做轨迹地图和运动数据的分析处理
    涉及到多个地图(百度、高德、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<BMKMapViewDelegate> 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、BKMap

        本文链接:https://www.haomeiwen.com/subject/zmiayftx.html