[as3] 从内存中删除 Object  (一)

从内存中删除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 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] 

    标记-清除算法相对于引用计数可能会花费较多的时间,也不会像后者那样频繁的执行.事实上,有时候它在影片中几乎是不执行的,当标记清除执行时,时间轴已经经过了好多帧了,也就是说,有时候你觉得变量已经从内存中删除掉了,而实际上它还会在内存中存在一段时间.对于那些与对象的脚本,比如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




[本日志由 jack 于 2007-09-04 05:00 PM 编辑]
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: as3 内存 删除 回收
相关日志:
评论: 0 | 引用: 0 | 查看次数: -
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.