AS3 內存回收機制

       AS3相對於以前版本的功能增強了很多,在賦予它重任時,同時也要它付出代價:垃圾收集器不再支持自動爲你收集垃圾。本文中,我爲大家整理了一些資料。首先,我們先來了解下垃圾收集器是個什麼東西?     
       (1)關於垃圾收集器
         垃圾收集器是一個後臺進程它負責回收程序中不再使用的對象佔用的內存。非活動對象就是不再有任何其他活動對象引用它。爲便於理解這個概念,有一點非常重要,就是要意識到除了非原生類型(Boolean, String, Number, uint, int除外),你總是通過一個句柄訪問對象,而非對象本身。當你刪除一個變量其實就是刪除一個引用,而非對象本身。
       (2)AS3的內存機制的方法: 
         <a>引用計數法:引用計數法是一種用於跟蹤活動對象的較爲簡單的方法,它從ActionScript1.0開始使用。當你創建一個指向某個對象的引用,該對象的引用計數器加1;當你刪除該對象的一個引用,該計數器減1.當某對象的計數器變成0,該對象將被標記以便垃圾回收器回收。
         
     var a:Object = {foo:"bar"}
  // the object now has a reference count of 1 (a)
  var b:Object = a;
  // now it has a reference count of 2 (a & b)
  delete(a);
  // back to 1 (b)
  delete(b);
  // down to 0, the object can now be deallocated by the GC
 
         <b>引用計數法簡單,它不會非CPU帶來巨大的負擔;多數情況下它工作正常。不幸地是,採用引用計數法的垃圾回收器在遇到循環引用時效率不高。循環引用是指對象交叉引用(直接、或通過其他對象間接實現)的情況。即使應用程序不再引用該對象,它的引用計數器仍然大於0,因此垃圾收集器永遠無法收集它們。下面的代碼演示循環引用:
       
     var a:Object = {}
  // create a second object, and reference the first object:
  var b:Object = {foo:a};
  // make the first object reference the second as well:
  a.foo = b;
  // delete both active application references:
  delete(a);
  delete(b);
         上述代碼中,所有應用程序中活動的引用都被刪除。我沒有任何辦法在程序中再訪問這兩個對象了,但這兩個對象的引用計數器都是1,因爲它們相互引用。循環引用 還可以更加負責 (a 引用 c, c引用b, b引用a, 等等) 並且難於用代碼處理。FlashPlayer 6 和 7的XML對象有很多循環引用問題: 每個 XML 節點被它的孩子和父親引用,因此它們從不被回收。幸運的是FlashPlayer 8 增加了一個叫做標識-清除的新垃圾回收技術。
          <c>標識-清除法 ActionScript3.0 (以及FlashPlayer 8) 垃圾回收器採用第2種策略標識-清除法查找非活動對象。FlashPlayer從你的應用程序根對象開始(ActionScript3.0中簡稱爲root)直到程序中的每一個引用,都爲引用的對象做標記。 接下來,FlashPlayer遍歷所有標記過的對象。它將按照該特性遞歸整個對象樹。並將從一個活動對象開始能到達的一切都標記。該過程結束後,FlashPlayer可以安全的假設:所有內存中沒有被標記的對象不再有任何活動引用,因此可以被安全的刪除。圖1 演示了它如何工作:綠色引用(箭頭)曾被FlashPlayer 標記過程中經過,綠色對象被標記過,白色對象將被回收。
       
       (3)AS3的內存機制的特點:
          1.  自動內存回收時間不確定。
          2.  當一個對象存在被其他對象引用時,這個對象不會被內存回收。
          3.  當一個流對象被加載,這個被加載的對象及已經佔用了內存。
          4.  當一個可視化對象被聲明,但沒有添加到畫面是佔用部分內存,加到displayObject上後,佔用全部該對象對象全部內存。
         5.  當加載重複對象,例如 加載100個同樣的 XX.swf ,如果僅是加載,完成後沒有引用,那麼內存變化規律,波浪型的。如果某個時間內存回收。那麼最後留在內存中的應該是大小近似於加載1個 XX.swf (比1個XX.swf 要大些),從此可以推理出,要是不同的東西被加載,那麼最後即便是沒有內存漏洞,在一定條件下常用的東西內存中可能也會至少保存每一個不同的東西。經我測試好像是這樣的。(測多了可能還會有新發現呢)
         6.  引用的包括
         1)  對對象的存儲: 例如 使用一個數組保存 某些對象,那麼數組不釋放,對象不可能釋放
         2)  對事件的監聽: 例如 監聽過程實際上是使用一個對象保存關鍵字和關鍵字關聯的事件,對事件關鍵字,查找然後找出對應的關聯function。以下是as2代碼。
         3)  強制回收方式,自動內存回收時間不確定,使用特殊的方法,該方法實際上觸發一個錯誤引起資源回收,使無用的不被計數器引用的都要被回收。(暫時不被使用的,沒有引用的那個被自動回收保留的那個一個回收掉),附件爲強制回收類。
 
         7.  編寫代碼注意:
         1)  無用的對象,沒有引用
         2)  降低類設計之間的耦合度,注意對象傳遞引用的設計等
         3)  單例模式,在合適的時候使用
         4)  事件循環嵌套造成多次執行,或事件觸發循環bug。
         5)  對象重複加同樣的監聽
       
        (4)AS3開發需要注意的地方:
         1. 被刪除對象在外部的所有引用一定要被刪除乾淨才能被系統當成垃圾回收處理掉;
         2. 父對象內部的子對象被外部其他對象引用了,會導致此子對象不會被刪除,子對象不會被刪除又會導致了父對象不會被刪除;
         3. 如果一個對象中引用了外部對象,當自己被刪除或者不需要使用此引用對象時,一定要記得把此對象的引用設置爲null; 
        4. 本對象刪除不了的原因不一定是自己被引用了,也有可能是自己的孩子被外部引用了,孩子刪不掉導致父親也刪不掉;
        5. 除了引用需要刪除外,系統組件或者全局工具、管理類如果提供了卸載方法的就一定要調用刪除內部對象,否則有可能會造成內存泄露和性能損失;
        6. 父對象立刻被刪除了不代表子對象就會被刪除或立刻被刪除,可能會在後期被系統自動刪除或第二次移除操作時被刪除;
        7. 如果父對象remove了子對象後沒有清除對子對象的引用,子對象一樣是不能被刪除的,父對象也不能被刪除;
        8. 註冊的事件如果沒有被移除不影響自定義的強行回收機制,但有可能會影響正常的回收機制,所以最好是做到註冊的事件監聽器都要記得移除乾淨。
        9. 父對象被刪除了不代表其餘子對象都刪除了,找到一種狀態的泄露代碼不等於其他狀態就沒有泄露了,要各模塊各狀態逐個進行測試分析,直到測試任何狀態下都能刪除整個對象爲止。
       
       (5)內存泄露舉例:
         1. 引用泄露:對子對象的引用,外部對本對象或子對象的引用都需要置null;
         2. 系統類泄露:使用了系統類而忘記做刪除操作了,如BindingUtils.bindSetter(),ChangeWatcher.watch()函數時候完畢後需要調用ChangeWatcher.unwatch()函數來清除引用 ,否則使用此函數的對象將不會被刪除; 類似的還有MUSIC,VIDEO,IMAGE,TIMER,EVENT,BINDING等。
        3. 效果泄露:當對組件應用效果Effect的時候,當本對象本刪除時需要把本對象和子對象上的Effect動畫停止掉,然後把Effect的target對象置null; 如果不停止掉動畫直接把 Effect置null將不能正常移除對象。
       4. SWF泄露:要完全刪除一個SWF要調用它的unload()方法並且把對象置null;
       5. 圖片泄露:當Image對象使用完畢後要把source置null;(爲測試);
       6. 聲音、視頻泄露: 當不需要一個音樂或視頻是需要停止音樂,刪除對象,引用置null;
 

 
附件爲強制回收類。調用方法:
import MyGc;
MyGc.GC()
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章