这段时间面试了两三家公司,有大公司也有小团队,他们都问了我关于flash的垃圾回收机制和我平时在项目里面怎么做到内存管理优化和CPU性能优化。其实我之前一直有去看着一块,开发过程中也刻意去关注这块,只是最近做逻辑功能比较多,把很多底层的知识都忘记了,说出来也是一块一块的。趁着现在有空就总结一下,有可能写不全或者不对,以后还会陆续修正和添加。
内存管理与加载优化
模块化
我之前负责的两个项目都是MMOARPG,两个项目整体的架构都是一致的,可能最大的不同就是前者没有模块化而后者有模块化。其实模块化最好的好处就是减少了主文件的大小,把一部分可以拆分的模块代码分别编译到不同模块的swf里面去,当需要某个功能模块的时候才去加载这个模块对应的swf文件。迟些我会特意写一篇文章去总结后者项目模块化的做法。
加载策略
说到游戏的资源加载,可以划分为两个阶段,分别是“游戏准备阶段”和“游戏运行时”。
“游戏准备阶段”是指从玩家进入游戏、选定角色、填写名字、等待加载、角色正式在场景。这个过程一般是由外壳去加载游戏的主文件和游戏开始前必须加载的资源(譬如常用皮肤、配置表等),完成这部分加载之后角色其实已经正式进入场景,部分UI界面已经初始化完毕了,在这个时间我们还可以进行背后加载。为了不影响玩家的体验,这个时候是看不到loading的图标的,所以我们才叫背后。我们可以用这个方法去加载一些功能模块的皮肤(譬如好友皮肤、邮件皮肤等),因为游戏刚开始玩家一般都不会去操作这些功能。
在“游戏运行时”这个阶段较优的加载策略主要是按需加载,需要什么则去加载什么,等加载完成我们再去初始化该部分。上面提到的模块化也是用这个思想去实现的。
使用cache
这里提的到cache包括了浏览器的cache、sharedObject实现的本地cache、对象池。有些玩家可能先去N服玩了一下,然后又跑去N+1服完,这个时候浏览器的cache就起到作用了,只要保证不同服的资源是从相同的CDN地址下获取的则可。不过这个有时候还得看运维的同事怎么去安排,这一个cache就不是我们客户端同志所需要花心思的地方。现在几乎所有flash的页游都有做本地缓存的机制,如果这个都没用就真的不好意思拿出来卖了。说到sharedobject,我推荐.minerva这个air工具,它可以用来查看本机保存下来的.sol文件。建议对象池用Vector去实现,因为它在某种情况下是优于Array的。对象池的实现方法和原理网上找找就有很多。
资源压缩策略
- xml配置表压缩成二进制。
- 模型根据动作分多模型(譬如站立、跑动、攻击等动作分多个swf)。
- 选择适当的图片格式(譬如有透明的用png,无透明的用jpg。jpg的可以选择80%的品质等等)。
- 利用swf格式压缩素材(因为本身swf里面的素材在编译成swf后都会被压缩成二进制)。
编码层面的优化
- 记得移除事件监听。
- 没用的对象记得释放(譬如数组设置为null,BitmapData调用dispose方法)。
- 能用回调函数的则替代事件派发,事件也占用内存的。
- Timer记得暂停与释放。
- 每个对象都应该使用正确的数据类型(譬如Sprite MovieClip Shape占用的空间大小都不一样)。
CPU优化
要做CPU的相关优化必须清楚认识flash的渲染机制。
- 减少在一帧里面需要执行的代码量,可以把部分代码推到下一帧执行。
- 减少重绘的区域个数与面积,推荐天地会的《深入理解Flash Player重绘》。
- 减少鼠标检测,不需要鼠标事件的尽量设置mouseEnabled和mouseChildren为false。
- 适当情况下使用cacheAsBitmap。
- 注意flash对位图的渲染效率是比Sprite MovieClip都要高。