AS3.0 一些有關內存泄露的問題

AS3.0中對偵聽器的改進遠遠不止以上這些,看一看addEventListener的實現接口:
function addEventListener(eventName:String, 
                          listener:Object,
                          useCapture:Boolean=false,
                          priority:Integer=0,
                          useWeakReference:Boolean=false):Boolean;
哇塞,有三個莫名奇妙的參數。可是當你知道這三個參數背後隱藏的巨大改進之後,相信你要大叫三個哇塞。

第一個神祕參數,目前暫不解釋,埋個伏筆,留到EventDispatcher那一節,講ActionScript3嶄新的Event Flow事件流機制.

第二個參數:優先級。

有趣吧,在ActionScript3.0中我們可以控制事件的優先級,從而達到控制function偵聽器的執行順序。如果你不填這個參數,那麼事件默認爲同一個級別0,事件的執行按先來後到的天經地義的順序。 

如果設爲1,那麼事件級別降一個檔次,稍後執行。數字越高優先級越高。級別可以爲負數。
(注意: Flex Builder 2 Beta3中事件級別是越低越高)

第三個參數,講的是是否設爲弱引用。
兄弟們初學As2.0時一定經常忘了在刪除Listener對象時,卻忘了removeEventListener吧。這會導致很多莫名奇妙的情況發生。也是最常見的詭異bug種類之一。即使老鳥偶爾也會被陰一把。
最鬱悶的是這種情況往往不被發現,在後臺默默的消耗大量資源。
現在可以用弱引用可以在某種程度上解決這種bug。
設爲true,就是告訴垃圾回收器,這個偵聽器function的引用是弱引用。一旦這個偵聽器在運行時只剩下了這一個弱引用,那麼垃圾回收器可以不理它,直接把它回收咯屁了,節省資源。
從AS3.0引入這個弱引用這個概念就可以看出,AS3.0是如何的重視資源管理和有效率的運用。一個標準的重量級的程序語言必須具有這樣的特徵。


=================


弱引用的使用原則


弱引用從原則上來講,其引入是爲了防止無意識的對象保留(unintentional object retention)引起的內存泄漏。
什麼是無意識的對象保留?一般情況下,對象的邏輯生命週期和實際生命週期應當相同。但是在某些情況下,比如事件偵聽器機制,我們可能會創建一個引用,它在內存中生存的時間比我們預期的要長很多。比如說,下面的例子中,即使刪掉了偵聽器lis,但事件還是能被繼續捕捉。這是由於並沒有removeEventListenr,那麼系統中還會保留着對偵聽器的引用。
如果沒有把addEventListener中對偵聽器的持有改成弱引用,那麼這個偵聽器會一直存在、耗掉內存不被人發覺。但如果設成了弱引用,那麼垃圾回收器過段時間後會將偵聽器佔用的內存回收,此時偵聽器從物理意義上才真正的被銷燬了。
在銷燬之前,這個偵聽器還會繼續存在,繼續作用。這就是爲什麼下例中雖然已經把useWeakReference設爲了true,但是還是會有作用。
那麼什麼時侯垃圾回收器(Garbage Collector)纔會來回收呢?
唔,這要看它高興了,快的話10分鐘,慢的話一個月。哈哈,開玩笑,垃圾回收器的工作時間咋一看確實是不可測的,但也有規律可循。


那麼推論來了,我們憑什麼要把useWeakReference設爲false呢?除非我們有意要讓某個偵聽器在失去了其他所有引用的時候還要工作,纔有可能這樣做。但誰會有這樣瘋狂的想法呢?道哥還是包世宏?
所以,我建議,大家不妨養成習慣,把useWeakReference設爲true。
當然最好的做法是始終記得不用偵聽器了,一定要removeEventListener。在這一點上,我們要堅持“始亂終棄”!!


//這個是Document Class,建個fla,綁定這個class。忘了,就看我第三篇教程。
package 
{
 import flash.display.MovieClip;
 import flash.events.EventDispatcher;
 import flash.events.MouseEvent; 

 public class LearnEvents extends MovieClip
 {
  function LearnEvents() {
   var lis:Function = function () {
    trace ("聽到了鼠標Click事件!");
   }
   var kingda_s:Kingdasprite = new KingdaSprite(0xFFCC00, "kingdaSquare");
   addChild(kingda_s);
   kingda_s.addEventListener(MouseEvent.CLICK, lis, false, 0, true); //瞧,最後一個參數,已經把弱引用設爲true了
   lis = null;  //這一句,我已經從邏輯上刪掉lis了,大家作證啊
   trace ("偵聽器還在嗎?:"+ lis);  //lis也確實指向null了。但你只要繼續點擊方塊,你會發現Click事件仍然被捕捉到。
  
  }  
 }
}
import flash.display.Sprite;
import flash.events.MouseEvent;


//這個類就是畫一個矩形,
class KingdaSprite extends Sprite {
 public var nickname:String;
 public var ColorNum:uint;
 
 //colorNumber就是#ffcc00這種類型的數,在AS3中推薦用新的uint型來標記它
 public function KingdaSprite(colorNumber:uint, nameString:String) {
  ColorNum = colorNumber;
  nickname = nameString;
  graphics.beginFill(ColorNum);
  graphics.drawRect(0,0,100,100);
  graphics.endFill();  
 }
 
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章