节省内存对于应用程序是非常重要的,必须限制应用程序占用的内存量,来提高用户的
1、选择合适的显示对象
常用到的显示对象有:Shape、Sprite、MovieClip。各个显示对象的内存使用量测试如下:
trace(getSize(new Shape())); //结果:248 trace(getSize(new Sprite())); //结果:424 trace(getSize(new MovieClip())); //结果:456
注:getSize()方法可以得到对象在内存中占用的字节数。
可以看出MovieClip比Shape的内存使用量大很多,使用不合理将会造成内存的浪费。对于这三个显示对象的使用原则是:对于非交互的简单形状,使用Shape对象;对于不需要时间轴的,但是需要交互的使用Sprite对象;对用使用时间轴的动画,使用MovieClip对象。
2、尽量重用对象
优化内存的另一个简单的方法是尽可能重复使用对象,避免重新创建对象。一下是一段创建平铺效果的代码,比较浪费内存:
var myImage:BitmapData; var myContainer:Bitmap; const MAX_NUM:int = 300; for (var i:int = 0; i < MAX_NUM;++i) { myImage = new BitmapData(20, 20, false, 0xF0D062); myContainer = new Bitmap(myImage); addChild(myContainer); myContainer.x = (myContainer.width + 8) * Math.round(i % 20); myContainer.y = (myContainer.height + 8) * int(i / 20); }
注:四舍五入使用Math.round()方法比较好。
优化后的版本仅仅创建了一个BitmapData示例:
var myImage:BitmapData = new BitmapData(20, 20,false,0xF0D062); var myContainer:Bitmap; const MAX_NUM:int = 300; for (var i:int = 0; i < MAX_NUM;++i) { myContainer = new Bitmap(myImage); addChild(myContainer); myContainer.x = (myContainer.width + 8) * Math.round(i % 20); myContainer.y = (myContainer.height + 8) * int(i / 20); }
优化后节省大大约700KB的内存,效果可观。
3、适当的时候使用对象池
涉及到不断重复使用对象的情形,可以考虑对象池。对象的原理是,在初始化应用程序期间创建一定数量的对象,存储到一个池中(例如Array或者Vector对象)。对一个对象完成操作后,释放掉该对象占用的CPU资源,然后删除所有相互的引用,将该对象放回到池中,在需要时可对其取出。
对象池可以减少示例化对象的操作,还可以减少垃圾回收期运行的机会,从而显著提高应用程序运行的速度。下面首先创建一个存放Sprite对象池作为示例:
package zhangqgc.util { import flash.display.Sprite; /** * Sprite 对象池 * @author zhangqgc */ public final class SpritePool { private static var MAX_VALUE:uint; //最大对象数 private static var GROWTH_VALUE:uint; //增长数量 private static var counter:uint; //对象池中剩余对象数 private static var pool:Vector.<Sprite>; //对象池 private static var currentSprite:Sprite; //当前对象 //初始化对象池 public static function initialize(maxPoolSize:uint, growthValue:uint):void { MAX_VALUE = maxPoolSize; GROWTH_VALUE = growthValue; counter = maxPoolSize; var i:uint = maxPoolSize; pool = new Vector.<Sprite>(MAX_VALUE); while (--i > -1) { pool[i] = new Sprite(); } } //获取对象 public static function getSprite():Sprite { if (counter > 0) { return currentSprite = pool[--counter]; } //对象不够用的,按照初始化时提供的增长数据量增长 var i:uint = GROWTH_VALUE; while (--i > -1) { pool.unshift(new Sprite()); } counter = GROWTH_VALUE; return getSprite(); } //销毁对象 public static function disposeSprite(disposedSpriete:Sprite):void { pool[counter++] = disposedSpriete; } } }
下面做个例子:开始从对象池中获取多个Sprite对象,在鼠标点击舞台时,将所有的对象回收。
package zhangqgc { import flash.display.Sprite; import flash.events.MouseEvent; import zhangqgc.util.SpritePool; /** * Sprite 对象池使用实例 * @author zhangqgc */ public class SpritePoolExample extends Sprite { public function SpritePoolExample() { const MAX_SPRITES:uint = 100; const GROWTH_VALUE:uint = MAX_SPRITES >> 1;//开方 const MAX_NUM:uint = 10; SpritePool.initialize(MAX_SPRITES, GROWTH_VALUE); var currentSprite:Sprite; var container:Sprite = SpritePool.getSprite(); addChild(container); for (var i:int = 0; i < MAX_NUM; i++) { for (var j:int = 0; j < MAX_NUM; j++ ) { currentSprite = SpritePool.getSprite(); //获取对象 currentSprite.graphics.beginFill(0x990000); currentSprite.graphics.drawCircle(10, 10, 10); currentSprite.x = j * (currentSprite.width +5); currentSprite.y = i * (currentSprite.width + 5); container.addChild(currentSprite); } } stage.addEventListener(MouseEvent.DOUBLE_CLICK, removeDots); function removeDots(e:MouseEvent):void { while (container.numChildren > 0) { SpritePool.disposeSprite(container.removeChildAt(0) as Sprite); //回收对象 } } } } }