节省内存对于应用程序是非常重要的,必须限制应用程序占用的内存量,来提高用户的
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); //回收对象
}
}
}
}
}