Flex内存优化专题之——1、垃圾回收机制

  Flash Player 垃圾回收工作是由垃圾回收器(garbage collector)完成的。垃圾回收器是
运行在后台的一个进程,它释放那些不再被应用所使用对象所占用的内存。不再被应用所
使用的对象是指那些不再会被那些活动着(工作着)的对象所“引用”的对象。在 AS 中,
对于非基本类型(Boolean, String, Number, uint, int)的对象,在对象之间传递的都是对象引用,
而不是对象本身。删除一个变量只是删除了对象的引用,而不是删除对象本身。一个对象
可以被多处引用,通过这些不同的引用所操作的都是同一个对象。  
  通过以下两段代码可以了解基本类型和非基本类型对象的差异: 
  基本类型的值传递:

  private function testPrimitiveTypes():void 
    {      
        var s1:String="abcd"; // 创建了一个新字符串 s1 ,值为 "abcd"     
        var s2:String=s1; //String 是基本类型,所以创建了一个新的字符串 s2 , s2 的值拷贝自 s1 。      
        s2+="efg"; // 改变 s2 的值 s1 不会受影响。      
        trace("s1:",s1);  // 输出 abcd     
        trace("s2:",s2); // 输出 abcdefg      
        var n1:Number=100; // 创建一个新的 number, 值为 100 。      
        var n2:Number=n1; //Number 是基本类型 , 所以又创建一个新 number n2,n2 的值拷贝自 n1 。      
        n2=n2+100;   // 改变 n2 对 n1 不会有任何影响。      
        trace("n1",n1); // 输出 100     
        trace("n2",n2); // 输出 200 
    } 

  非基本类型对象的引用传递:    

  private function testNonPrimitiveType():void          
    {             
        // 创建一个新对象 , 然后将其引用给变量a :                 
        var a:Object = {foo:"bar"}                
        // 将上面所创建对象的引用拷贝给变量b(通过变量b建立对对象的引用) :                  
        var b:Object = a;               
        // 删除变量 a 中对对象的引用 :                  
        delete(a);               
        // 测试发现对象仍然存在并且被变量 b 所引用:                 
        trace(b.foo); // 输出 "bar", 所以对象仍然存在          
    }

   对于非基本类型对象,AS3 采用两种方法来判定一个对象是否还有活动的引用,从而

决定是否可以将其垃圾回收。一种方法是引用计数法,一种方法是标记清除法。 

 Reference Counting

  引用计数法是判定对象是否有活动引用的最简单的一种方法,并且从 AS1 就开始在
Flash 中使用。当创建一个对对象的引用后,对象的引用计数就加一,当删除一个引用时,
对象的引用技术就减一。如果对象的引用计数为0,那么它被标记为可被 GC(垃圾回收器)
删除。例如:  

  var a:Object = {foo:"bar"} 
    // 现在对象的引用计数为1(a) 
    var b:Object = a; 
    // 现在对象的引用计数为 2(a 和b)  
    delete(a); 
    // 对象的引用计数又回到了 1 (b) 
    delete(b); 
    // 对象的引用计数变成 0,现在,这个对象可以被 GC 释放内存。

   

  引用计数法很简单,并且不会增加 CPU 开销,可惜的是,当出现对象之间循环引用时它就
不起作用了。所谓循环引用就是指对象之间直接或者间接地彼此引用,尽管应用已经不再
使用这些对象,但是它们的引用计数仍然大于0,因此,这些对象就不会被从内存中移除。
请看下面的范例:   

  //创建第一个对象:  
    var a:Object = {}; 
    // 创建第二个对象来引用第一个对象: 
    var b:Object = {foo:a}; 
    //使第一个对象也引用第二个对象: 
    a.foo = b; 
    // 删除两个活动引用: 
    delete(a); 
    delete(b);

   上面的例子中两个活动引用都已被删除,因此在应用程序中再也无法访问这两个对象。但

是它们的引用计数都是1,因为它们彼此相互引用。这种对象间的相互引用可能会更加复
杂(a 引用 b,b 引用 c,c 又引用 a,诸如此类),并且难以在代码中通过删除引用来使得引
用技术为变为0。Flash player 6 和 7 中就因为 XML 对象中的循环引用而痛苦,每个 XML
节点既引用了该节点的子节点,又引用了该节点父节点。因此,这些 XML 对象永远不会释
放内存。好在 player 8 增加了一种新的 GC 技术,叫做标记清除。

标记清除(Mark Sweeping)

  AS3 使用的第二种查找不活动对象的 GC 策略就是标记清除。 Player 从应用的根节点
开始(在 AS3 中通常被称为”根(root)”),遍历所有其上的引用,标记每个它所发现的
对象。然后迭代遍历每个被标记的对象,标记它们的子对象。这个过程第归进行,直到
Player 遍历了应用的整个对象树并标记了它所发现的每个东西。在这个过程技术的时候,
可以安全地认为,内存中那些没有被打标记的对象没有任何活动引用,因此可以被安全地
释放内存。可以通过下图可以很直观地了解这种机制(绿色的引用在标记清除过程中被遍
历,绿色对象被打上了标记,白色对象将被释放内存)

 

         

  标记清除机制非常准确,但是这种方法需要遍历整个对象结构,因此会增大 CPU 占用 率。

  因此,Flash Player9 为了减少这种开销只是在需要的时候偶尔执行标记清除活动。 

  注意:上面所说的引用指的是“强引用(strong reference)”,flash player 在标记清
除过程中会忽略“弱引用(weakness  reference )”,也就是说,弱引用在标记清除过程
中不被当做引用,不会阻止垃圾回收。

 

 

 

posted @ 2012-12-18 15:11  小小有  阅读(203)  评论(0)    收藏  举报