[as3] 从内存中删除 Object (一)
作者:jack 日期:2007-09-04
从内存中删除Object (一)
jackgun_at_126.com
先看看以下这段关于垃圾回收机制的文字,从雨飞那抄来的
45.无用单元回收:引用计数算法和标记-清除算法
Flash中的无用单元回收机制(Garbage Collection)用来自动清除内存中不再需要的变量,有两种算法执行:
引用计数 和 标识和清除.
引用计数用来追踪内存中对象的所有引用,当我们创建一个指向这个对象的引用时,它的引用计数就进行增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
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]
标记-清除算法相对于引用计数可能会花费较多的时间,也不会像后者那样频繁的执行.事实上,有时候它在影片中几乎是不执行的,当标记清除执行时,时间轴已经经过了好多帧了,也就是说,有时候你觉得变量已经从内存中删除掉了,而实际上它还会在内存中存在一段时间.对于那些与对象的脚本,比如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)来回收无用侦听器,是一个好的习惯.
--------------------------------------------------------------传说中的分割线---------------------------------------------------------
OK!
我们来试试….
建个 Test 类
package {
import flash.display.Sprite;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Test extends Sprite {
private var time : Timer;
private var i : int = 0;
public function Test() : void {
time = new Timer(500, 0);
time.addEventListener("timer", runmovie);
time.start();
}
private function runmovie(event : TimerEvent) : void {
i++;
trace("---testing....." + i);
}
}
}
MainDocumentClass:
package {
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.system.System;
import flash.events.TimerEvent;
public class MainDocumentClass extends MovieClip {
public var testobj : Test;
private var time : Timer;
private var i:int=0;
public function MainDocumentClass() : void {
testobj = new Test();
addChild(testobj);
time = new Timer(500, 0);
time.addEventListener("timer", runmovie);
time.start();
}
private function runmovie(_event : TimerEvent) : void {
i++;
if(i==6){
trace("移除 testobj");
removeChild(testobj);
testobj=null;
}
trace("==" + System.totalMemory);
}
}
}
新建 fla 测试以上代码,你会发现 Test 类被删除后仍然在工作,不是说通过引用计数来确定是否符合回收机制吗?丢!鬼知道会不会被回收啊…..
干嘛不干净点让我们自己删…
待续…
jackgun_at_126.com
上一篇
下一篇

文章来自:
Tags: