引用计数 和 标识和清除.
引用计数用来追踪内存中对象的所有引用,当我们创建一个指向这个对象的引用时,它的引用计数就进行增1操作.
var a:Object = new Object(); // new Object in memory given reference count of 1 var b:Object = a; // Object now has reference count of 2
当内存中不再存在任何指向这个对象的引用时,无用单元回收器(GC)会将这个对象从内存中清除掉.
delete a; // Object has reference count of 1
delete b; // Object has reference count of 0, removed from memory
要注意的是,delete 操作符只是用来删除相关的变量,但是,它并不会将对象从内存中清除掉,那是无用单元回收器的工作,还有,delete 操作符不能删除类成员变量.
引用计数在有些时候并不能正常工作.例如,如果你定义两个对象,它们只是引用自身,而没有任何别的对象引用它们,这样它们的引用计数是大于0的,可以却没有办法访问到它们.
var a:Object = new Object(); // reference(a) count 1 var b:Object = new Object(); // reference(b) count 1 a.b = b; // reference(b) count 2 b.a = a; // reference(a) count 2 delete a; // reference(a) count 1 delete b; // reference(b) count 1
这里对象a和对象b已经从当前作用域内删除掉(delete)了,所以它们是没有办法访问到的.但是,从对象a仍然是可以访问对象b的,而且对象a也可以从对象b访问到.对象a和对象b看起来已经被程序员手动删除一样,而实际上,它们还存在于内存中,而且它们的引用计数还大于0的,所以这种情况下引用计数有很大的缺陷,而标记-清除算法可以解决.
标记-清除算法是这样一个过程,程序会在一个基础的区域(比如root或舞台stage)扫描所有的对象和引用,标记出已经发现的,那些没有发现的是不能被访问到,或者已经被删除(delete)掉的.还拿上面对象a和对象b的例子来说,因为对象a和对象b都不能被根目录(root)下任何对象访问到,它们不会被标记,最后会被无用单元回收器(GC)清理掉.
//扫描过程描述 [root] <- scan...
[objectRef (marked)] <- scan... [objectRef (marked)] <- scan... [objectRef (marked)] <- scan... [objectRef (marked)] <- scan... [objectRef (marked)] <- scan... ...
[delete all objects not marked]
36
标记-清除算法相对于引用计数可能会花费较多的时间,也不会像后者那样频繁的执行.事实上,有时候它在影片中几乎是不执行的,当标记清除执行时,时间轴已经经过了好多帧了,也就是说,有时候你觉得变量已经从内存中删除掉了,而实际上它还会在内存中存在一段时间.对于那些与对象的脚本,比如enterFrame事件,当对象实际删除之前这些事件还在执行,所以你始终应该记得在不使用的时候清除(clearup)你的事件. 46.弱引用(Weak Reference)
如果你想使用一个不被GC计数的引用,可以定义一个弱引用.弱引用会被引用计数器忽略掉,即使引用的对象被删除(delete)了,而弱引用还可以存在.
AS3.0中的弱引用是不能到处使用的,只能在以下两个地方使用:一是用于Dictionary对象,Dictionary类的构造器使用一个可选择的参数来决定Dictionary实例的键值是否使用弱引用.默认情况下为false,使用的是强引用,如果设置为true,使用弱引用.
var dict:Dictionary = new Dictionary(true); // use weak references as keys
如果你做了上面的操作,那么你用来存放数据的键值不会被算做对象的引用,也就是对象引用计数不会增加.
var obj:Object = new Object(); dict[obj] = true;
delete obj; // obj can be garbage collected since the dict reference isnt counted
另外可以在EventDispatcher类的addEventListener方法指定弱引用,addEventListener方法有一个参数可以用来指定侦听器引用为弱引用.注:这里不明白的可以参考黑羽的教程
// addEventListener(type:String, listener:Function, useCapture:Boolean= false, priority:int = 0, useWeakReference:Boolean = false):void
addEventListener(MouseEvent.CLICK, clickHandler, false, 0 true); // use weak references
默认情况下这个参数也为false,使用强引用,这里指定侦听器引用为弱引用,从而调用无用单元回收器(GC)来回收无用侦听器,是一个好的习惯. 47.Flash 9:BitmapData类和库中位图的使用
Flash 8 中,使用链接标号(linkage ID)和BitmapData.loadBitmap()方法可以加载库中位图信息.Flash 9和AS3.0中和时间线上的脚本,库中的影片剪辑一样,位图也可以与类关联的.如果你没有给库中位图定义好要关联的类,你可以直接命名一个类,编译器会在影片发布时自动创建这个类.
要注意的是自定义的关联类必须继承自BitmapData类(flash.display.BitmapData),和其它类一样使用new关键字来声明实例.BitmapData实例不能直接显示在屏幕上,它们需要与一个Bitmap实例(flash.display.Bitmap)关联,因为BitmapData对象不能被添加到显示列表(display list)中.而Bitmap对象属于显示对象(display object),可以添加到显示列表(display list)中.
举个例子,在库中导入一个名为Rome的位图文件,在位图元件的链接(linkage)对话框中设置一个RomeImage的类名,注意,你不必自己事先定义好这个类,它在影片发布时会被自动创建,然后,通过关联Bitmap对象把BitmapData实例显示到屏幕上
37
// create instance of RomeImage bitmap data
var romeImageData:RomeImage = new RomeImage();
// create a bitmap instance that references the RomeImage instance var romeImageBitmap:Bitmap = new Bitmap(romeImageData); // add the new bitmap to the display list addChild(romeImageBitmap);
48.typeof运算符的变化
使用 typeof 运算符可获取数据的基本类型,但是, typeof 不能返回实例属于哪个类的信息,使用instanceof, getQualifiedClassName, describeType 可以获取更多的关于类的信息. 在AS1/AS2时,typeof 返回下列值:
* boolean * function * movieclip * null * number * object * string * undefined
而AS3.0中的typeof返回:
* boolean * function * number * object * string * xml
* undefined
我们注意到MovieClip实例在AS3中已经不再被typeof运算符识别了,而是看做object类型,此外,AS3中没有null类型了(同样也被视为object了),而增加了一个xml类型,用来识别xml对象.
AS3中的两个新的数值类型,uint和int,使用typeof都返回number.另外,使用boolean,Number和string等原始数值(primitive values)的构造函数和new关键字生成的数据都会被typeof识别为它们的原始类型,而不像在AS1/AS2时那样返回object.
// AS1& AS2
trace(typeof new XML()); // object trace(typeof my_mc); // movieclip trace(typeof null); // null
38
trace(typeof true); // boolean trace(typeof 1); // number trace(typeof \
trace(typeof new Boolean()); // object trace(typeof new Number()); // object trace(typeof new String()); // object // AS3
trace(typeof new XML()); // xml trace(typeof my_mc); // object trace(typeof null); // object trace(typeof true); // boolean trace(typeof 1); // number trace(typeof \
trace(typeof new Boolean()); // boolean trace(typeof new Number()); // number trace(typeof new String()); // string trace(typeof int(1)); // number trace(typeof uint(1)); // number
49.getBounds()和getRect()对比
和AS1/AS2时一样,AS3.0仍然使用getBounds()(flash.display.DisplayObject.getBounds())方法来获取一个影片剪辑的边界(bounds),不同的是,getBounds()方法返回值在AS3中变成了Rectangle对象(flash.geom.Rectangle),而不是AS1/AS2时的带有xMin,xMax,yMin和yMax属性的一般对象(generic object).
AS3中增添了一个类似GetBounds()的方法getRect()(flash.display.DisplayObject.getRect()) ,这个方法和getBounds()唯一的不同是忽略了图形的笔触宽度. 下面的例子说明两者返回值的不同:
var sprite:Sprite = new Sprite(); sprite.graphics.beginFill(0x999999); sprite.graphics.lineStyle(10, 0x333); sprite.graphics.drawCircle(100, 100, 50); sprite.graphics.endFill(); addChild(sprite);
addChild(createRectShape(sprite.getRect(this), 0xFF00FF)); addChild(createRectShape(sprite.getBounds(this), 0xFF0000)); function createRectShape(rect:Rectangle, color:uint):Shape { var rectShape:Shape = new Shape(); rectShape.graphics.lineStyle(0, color);
rectShape.graphics.drawRect(rect.left, rect.top, rect.width, rect.height); return rectShape; }
39
运行上面的脚本,画出一个笔触宽度为 10 px的圆,周围有两个矩形,一个正好适合圆形的矢量(vector shape)部分(getRect),另一个包含着包括圆形的笔触宽度在内的整个圆形(getBounds). getRect() 方法返回Rectangle对象与(除去10px 像素笔触宽度之后的)显示对象(display object)的长和宽关连,而getBounds()方法返回Rectangle对象与整个显示对象的可视区域关连.注意:两个方法都不把滤镜计算在内. 50.for?in和for each?in
AS3有一个新的迭代语句(interation statement):for each..in , 它的工作原理和for?in相似,不同之处它循环执行是时间轴上的实例或循环执行对象,而不是这些对象的键值(注:或者叫属性).
var object:Object = new Object(); object.name = \object.id = 2867;
object.isModerator = true; for each (var value:* in object){ trace(value); }
/* Output: true 2867 senocular */
for?in中执行的情况:
var object:Object = new Object(); object.name = \object.id = 2867;
object.isModerator = true; for (var key:String in object){
trace(key + \}
/* Output:
isModerator: true id: 2867
name: senocular */
注意在for each..in中键值是访问不到的.
AS3中仍然沿用数组单元排序(使用数值数组) ,而不像AS1/AS2时按照创建时的顺序排序.例如:
当使用for?in和for each?in循环数组时,ActionScript 3维持基本的数组元素顺序(使用数字列阵索引),而在AS1/AS2中会按数组创建时的顺序循环.例如:
40