优化内存

223 阅读6分钟

发生场景

接受服务器数据,在控件上重新演示播放客户端的动作,并添加特效

播放烟花效果

演示客户端的动作,使用Canvas绘制Path;Path通过服务器传过来的点的坐标,按一定时间逐个绘制点就能完成动画的效果,达到重现动作的效果

在根据点绘制想的过程,需要加上一个特效;特效是播放gif,并让gif在一定时间之后消失

问题

  1. 在绘制数量较大的时候,内存容易oom

  2. 有时候在绘制的时候,会突然崩溃

  3. 绘制速度过快,会丢失部分绘制过程

解决过程

问题3的解决过程

在绘制快速的时候,查看了服务器发送的数据是否和绘制过程数据一致;结果:数据一致

判断:

应该是android在一次性接受过多数据的时候,漏写入了数据

继续检查接收到数据,是怎么写入的

发现:

在接收到数据后,需要做json解析;这个点,暂时没考虑

继续下去发现,只有一个二维数组在接受数据

考虑:

一个二维数组在接受两个数据的时候,会是什么情况

情况不明;考虑到现在使用情况是频繁的写入,读取,没有查看的操作

使用LinkedList,一边可以直接写,一边直接poll出来,无需考虑其他

使用LinkedList优势:插入的时候,不会新建列表;这里无需这个功能;取出的时候,无需考虑index

劣势:查询特别不方便,要遍历整个列表【但是这里不要这个功能


问题2是偶发性的,所以没特意注意;结果在解决问题1的时候,顺带就解决了


问题1的解决过程

考虑到gif耗性能,尝试使用canvas来手动绘制,结果后面成功绘制了相似的动画效果,但是无法使用到绘制复现的过程;

请教外援

结果:

回应,使用gif是可以实现特效的;特效是在短时间内绘制的,之后可以回收使用过的内存

使用canvas也可以绘制;但是耗时,又要重新做别人完成过的内容,不合算;暂时抛弃

转头继续使用gif解决问题

使用工具android profile来查看运行过程中的内存使用情况

发现演示设备的性能低于开发设备,演示设备在使用内存240+M的内存就会oom,开发设备使用内存280M都很正常使用

测试回收gif的代码;发现并没有什么大的效果;原来的很多代码其实对于内存的回收,并没有作用

查看代码,发现在复现绘制路线的时候,使用了for循环;在这个时候如果还没有绘制却将所有数据都放在了内存,就相当于复制了一边数据;于是修改成了递归的方式,降低了循环,并使用view的postDelay方式在使用的时候再继续递归下一次任务,内存确实降低了很多;但是最后的内存还是很多;降低的只是过程中的内存

修改gif加载过程;使用对象池来管理已经加载过的gif对象,再gif消失的时候,直接将GifDrawable放入对象池,后面新的路径,可以直接从对象池中获取gif对象;

队列使用:

考虑数据结构需要在频繁写入、读取的过程不能重新新建列表;新建列表速度太慢了

AI建议:

使用双端队列或者优先队列

这里使用了双端队列;情况改成了:频繁的写入、取出;写入到第一个,取出总是取最后一个;

这样可以保证:

  1. 没消息的时候,数组内不会有数据

  2. 接受的消息,在复现的时候,顺序不会错

烟花的gif,因为烟花比较少的原因,手点击比较,慢,所以考虑使用原型模式;

结果:

成功得到烟花的GifDrawable,但是不能recycle,会报错;这时候发现,原来问题2就是使用了recycle方法,导致程序崩溃;这个方法直接弃用;因为这里要复用GifDrawable,不能recycle

发现recycle必须在存放gif的view不可见的时候,才可以正常调用;

而且就算使用克隆方法克隆出了新的GifDrawable,但是一旦recycle,后面就无法克隆了;

这个方法直接霸气不用;

直接克隆后,发现成功展示了烟花;结果烟花模糊了;

发现是程序没退出,Glide的内存保存了前面的烟花,复制出来继续播放;

关闭Glide的缓存功能;这里没有使用这个功能

成功展示烟花;但是克隆出来的烟花,有问题:

烟花消失后,后面克隆的烟花,又把消失的烟花显示出来;而且动作一致

尝试别的方式克隆;依然没得到解决;直接采用上面的对象池技术;再来一次

成功解决;但是

烟花需要完整的播放完毕动画,才能给其他控件复用;所以必须要等烟花结束再回收复用

结果,回收复用的时候,发现复用的烟花,不是从最开始的时候播放烟花

使用Glide想得到烟花gif的时间长度,没成功

使用其他软件查看gif时间,设置进去,发现时间不对;应该是有程序的运行时间,或者这个时间就是不对的

果断放弃了Glide;使用了android-gif-drawable

成功获取gif时间,在播放结束的时候,reset了一下,再回收;再次展示;完美解决

查看gif大小是56k,通过gif编辑,缩小到16k;效果差不多;但是加载gif的内存肯定减少的

解决结果

问题3解决,在测试的时候,就算很快的用手绘制,也能正常复现,没有出现丢失过程的现象

问题1解决,运行一段时间后,内存不会增长太快,就是开始一直创建对象的时候会吃内存;但是你一开始就要展示这么多gif,一样的吃内存,我把内存都复用了,后面就是多了一个路径保存的内存,gif变成了内存中一直复用的一段内存;中间加载gif过程的内存,反而回收了

问题2解决,遇到偶发性的问题,别急;先解决其他的