Weex-iOS内存分析
前言
引入weex提高了业务开发的效率以及灵活度,但是在使用过程中还是存在不少问题,其中内存上就有很明显的问题
一、weex页面与原生页面对比存在的内存问题
1、weex页面内存开销过大
如图进行页面切换:
在进行到weex页面的时候内存暴涨。
2、页面Push跳转堆栈内存泄漏。
从首页Push跳转到weex页面,加载数据,再返回,重复多次得出下图的结果:
而Push跳转到原生页面再返回,重复多次得出下图内存结果:
从上面两张图可以看出:原生页面返回后从堆栈移除后会进内存回收;而从weex页面回到首页,内存没有完全回收,存在一定的内存泄漏,重复多次可以看到内存相比较一开始会有明显的增加。
3、列表滑动的内存情况
在没有采用<list>和<cell>标签的情况下:
weex页面列表滑动内存情况如图:
weex页面滑动内存情况通过趋势图列表滑动过程中内存一直持续暴涨,没有进行复用减少内存开销。
原生页面列表滑动内存情况如图:
原生页面滑动内存情况从图中可以看到,在滑动初始阶段,内存增长比较快,之后的滑动过程中对前面的控件进行复用,内存开销减少,曲线变得平缓,没有出现内存持续暴涨。
4、 weex页面内存问题总结:
1、weex页面滑动没有采用复用机制,导致内存会跟着滑动持续暴涨
2、weex页面占用内存开销过高,多个weex页面可能导致APP因为内存过大而Crash。
3、weex页面从堆栈移除内存没有完全回收,存在一定的内存泄漏。
二、内存问题原因分析
1、滑动过程内存持续暴涨问题
weex官方文档上,建议使用高性能可复用<cell>
和<list>
,而【搜索页】、【乐疯抢】等weex页面业务代码中直接采用了<div>
和<scroller>
实现列表的布局,导致内存问题的出现。
这里我们通过Weex源码,对四个标签进行分析
可以在WXSDKEngine
中可以看出各个标签对应的类:
<div> 对应WXComponent
<scroller>对应WXScrollerComponent
<cell>对应WXCellComponent
<list>对应WXListComponent
<div>
<div>
对应的WXComponent
相当于原生iOS控件的UIView,是所有视图的基类,一个普通的视图没有性能优化、复用回收的机制。
<scroller>
<scroller>
对应的WXScrollerComponent
结构如下:
并无相关复用回收的属性,主要是提供一个可以滑动的容器。
<cell>
查看<cell>
对应WXCellComponent
类的实现代码可以发现,WXCellComponent
相比较WXComponent
拥有复用回收的相关属性isRecycle
<list>
<list>
对应的WXListComponent
的结构如图:
在成员列表中可以看到使用了iOS原生的UITableView,并且实现了使用了UITableView的代理方法,实现了iOS的复用机制,如图:
同时WXListComponent
实现了WXCellComponent
中的代理方法,WXCellComponent
与WXListComponent
相关联系。
因此<list>
基于iOS的UITableView复用机制,实现高性能了可复用的列表容器。
结合<cell>
可以实现一个高性能的列表展示页面。
因此采用<list>
和<cell>
代替<scroller>
和<div>
解决滑动列表内存暴涨的问题。
2、weex页面内存开销过高的问题
通过Instrument工具进行内存分析,发现在进入weex 页面时VM ImageIO_GIF_Data
和VM ImageIO
两个对象内存异常暴涨。
VM ImageIO_GIF_Data 内存增长情况:
VM ImageIO 内存增长情况:
VM ImageIO_GIF_Data
由7.92M增长到16.55M,VM ImageIO
由0.11M增长到了1.02M,进入Weex页面时,这两个对象总共增加了9.54M,而整个Weex页面初始状态占用内存为15M左右(原生【商品详情】页:7M左右),占据了整个Weex页面内存的约60%。而在原生页面中,
VM ImageIO_GIF_Data
和VM ImageIO
对象几乎没有增长。而这两个对象与
CoreGraphics
中进行图片绘制、图片渲染、图片读写等相关方法有关,而CoreGraphics为相对底层的模块,相关方法比较消耗性能、内存,并且容易产生内存泄漏。初步可以判定,weex中大量调用了
CoreGraphics
中图片处理的相关方法,导致了weex页面内存开销过大。
接着在WeexSDK的源码中查找CoreGraphics
相关方法,定位问题。
在查找过程发现,weex通过CoreGraphics绘图方法将<text>等控件实例绘制成位图进行显示,以适应weex中的CSS布局。
在 WXComponent+Display
中,可以看到将控件绘制成图片的代码,并在layer
上显示:
通过这部分的代码可以定位到weex页面内存开销过大的主要原因是: weex SDK 调用了CoreGraphics
方法将页面中的<text>等控件绘制成图片再布局显示,占用了大量的内存。
weex的内存泄漏也与大量调用了CoreGraphics
中方法有关。
通过Leaks工具定位到weex页面内存泄漏对象为CGDataProviderCreateWithCopyOfData
而
CGDataProviderCreateWithCopyOfData
为调用CoreGraphics
相关方法产生的对象。weex SDK调用
CoreGraphics
中的相关方法,但是没有及时地释放对象,导致了内存泄漏。
weex SDK 大量CoreGraphics
方法将控件绘制成图片再布局显示,占用了大量的内存,同时也导致了资源回收不及时的问题。
解决方案:
1、限制堆栈中weex页面个数:
天猫采用的也是该方案,通过控制页面级数,控制内存,防止因为堆栈过多的weex页面,内存过大导致异常Crash。
2、页面复用:
在打开weex页面前,判断堆栈中是否有该weex页面,如果有便进行页面复用,通过数据刷新页面,同时通过调整堆栈将页面显示出来。