iOS内存优化——OperationQueue悄悄给你挖的坑

前言

这篇文章是对以前我们的APP做过的一次内存优化的介绍,场景是在大批量(数千至上万)的小文件(JSON、图片)数据下载的情况,使用NSOperationQueue和dispatch_global_queue的一些注意点,有类似大批量数据的上传或下载需求的童鞋可以参考一下。

一、基本概念

队列的使用场景

在iOS的开发中,我们经常会需要处理一些耗时操作,比如网络请求、文件读写、数据库增删改查等等,这时候,如果对UI没有依赖操作,我们一般会开辟一个异步线程去做这些耗时任务。

  • 有时我们会遇到需要按顺序处理一批数据的情况,它们的处理方式依然按照上面所说的方式去处理,不过这种情况下,我们就会使用operation结合queue的形式来保证它们异步按顺序执行。

  • 当希望批量的耗时任务按大概的顺序并较快完成时,我们可以把operation加入queue,并设置一个合理的并发数。

二、问题

  • 每个耗时的operation本身需要一个对象去承载,即记录这次任务执行包含的必要信息,当它被加入队列以后,这个operation对象会被queue占有,保证任务执行完成之前***不被内存释放***。

  • 当operation数量十分巨大且队列处理任务的速度小于任务的添加速度时,那么***内存峰值***就会持续上升,如果这个峰值大于系统所能给当前APP分配的可用内存时,不用想——didReceiveMemoryWarning->Terminated due to Memory Error.

三、解决方案

既然问题出在使用队列造成了过大***内存峰值***上,那么肯定就从降低内存峰值下手咯,降低内存峰值的直接办法就是控制队列的最大任务数。

  1. 将需要执行的任务信息存入硬盘(plist、database),每次取出定量的任务加入队列处理,为保证充分利用cpu,任务数降低到并发数之前再次从硬盘取出定量的任务加入队列。
    这种情况适用于一些文件读写操作等单个文件本身需要耗费大量内存或者批量文件上传下载的情况。

  2. 将需要执行的任务最简单的基本信息放入内存(数组、字典),每次从内存中取出基本信息创建一个完整的operation加入队列。数量控制同1。
    这种情况适用于网络请求等只需要保存必须参数信息,且信息量很小,而发送网络请求创建request operation时可以再添加基础参数的情况。

四、场景实战

在我工作中负责维护的一款APP中,允许用户离线对数据进行操作,这就要求把用户所有的数据进行缓存。

在用户使用一个新的设备首次登录进入APP时,我们需要下载所有的用户数据,经测试在用户的数据量较大时,数据缓存到一定量时,APP就因为内存问题被系统kill了。

经过分析问题就是出在operation queue的使用上面,在queue中的待下载任务数量达到8000以上时在iPhone6上面就基本必现crash。

依照三、2中的方案对此处进行了队列任务数量的控制,降低内存峰值在可控范围内,基本保证用户首次使用需要加载数据量达到数万也不会crash。

五、拓展

在批量的文件下载中尤其需要注意:

如果文件的下载速度十分快,如果把下载任务和下载完成后的文件本地写入任务都放入同一个异步队列(比如全局并发队列),且下载任务优先级高于文件本地写入任务的优先级的情况时,有可能就会有大量的文件下载完成待写入,会消耗大量的内存,形成较高的内存峰值。

此时解决方案可能需要结合三同时对任务的优先级做控制。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值