flex 強制垃圾回收

  java和flash的垃圾回收都是一個比較熱門的話題,今天我也用一個例子來測試下flash的強制垃圾回收。主要用到的而一個類是LocalConnection。java

 

     在Flash player的debug版本中提供了gc的方法瀏覽器

   

 

   

 

     Flash Player初始化運行時,會向操做系統申請一大塊內存,若是程序很小,有可能根本用不了這麼多內存,但FP在開始時不考慮這些,大多數狀況下,第一次申請的內存老是不夠用的。第一次申請的內存大小,與操做系統、瀏覽器環境有關。性能優化


    當Flash Player發現已經申請的內存不夠用時,它會再向操做系統申請一大塊內存。但在申請以前,請注意,FP會嘗試進行垃圾內存回收。那麼它是如何回收的呢?
    Flash Player在內部使用懶惰式引用計數回收方案進行垃圾內存回收。函數

    懶惰式指:FP並不會一次把全部能夠回收的對象所有回收,它一次僅會回收一部分,若是內存不夠用,它會向操做系統申請,若是系統無內存了,它會再次回收,若是所有回收了仍不夠用,Game Over!工具

    引用計數指:FP在內部給每一個對象標記一個記號,當沒有任何對象引用此對象時,它便是能夠被回收的;若是一個容器內有許多相互關聯的對象,當把這個容器從顯示列表中移除,而且置爲null後,它也是能夠被回收的。性能

   
    在清楚了FP的內部垃圾回收機制以後,咱們能夠建立兩次沒用的LocalConnection,而且鏈接並不存在的地址,故意拋出異常而後捕獲,就強制垃 圾回收,由於,在AS3中LocalConnection是比較佔用內存的對象,兩次建立該類對象並嘗試進行鏈接的內存開銷大小足以請Flash Player從新向操做系統申請內存,而在申請以前,FP會嘗試回收。原理便是這麼簡單,非獨使用LocalConnection能夠,其它較耗內存的對 象也能夠。測試

 

    下面是我寫的測試代碼,主要測試三中狀況下內存的使用狀況。優化

   

Java代碼   收藏代碼
  1. package  
  2. {  
  3.     import flash.display.Sprite;  
  4.     import flash.external.ExternalInterface;  
  5.     import flash.net.LocalConnection;  
  6.   
  7.     public class MemeryGcTest extends Sprite  
  8.     {  
  9.         private const num:int = 30000//子元素個數  根據本身的電腦配置來設置  
  10.           
  11.         private var parentContainer:Sprite;//父容器   
  12.         private var childrenRect:Array;//全部子元素的引用         
  13.                
  14.         public function MemeryGcTest(){  
  15.             init();         
  16.         }          
  17.         private function init() : void{    
  18.             parentContainer=new Sprite();  
  19.             addChild(parentContainer);   
  20.             createAllChildrens();  
  21.             removeAllchildrens();  
  22.             setChildrenNull();  
  23.             //doGc();  
  24.         }  
  25.           
  26.                 
  27.         /** 
  28.          * 移除全部對象 
  29.          *  
  30.          */  
  31.         private function removeAllchildrens():void {            
  32.             removeAllChildrens( );             
  33.                        
  34.             removeChild(parentContainer);            
  35.                     
  36.         }  
  37.         /** 
  38.          * 設置不用對象爲null 不然不會進行垃圾回收  
  39.          *  
  40.          */  
  41.         private function setChildrenNull():void{  
  42.             childrenRect = null;  
  43.             parentContainer = null;  
  44.         }    
  45.         /** 
  46.          * 建立全部子元素  
  47.          *  
  48.          */  
  49.         private function createAllChildrens() : void {            
  50.             childrenRect=new Array();             
  51.             for(var i:int = 0;i<num; i++){  
  52.                 var sprite:Sprite=new Sprite();  
  53.                 childrenRect.push(sprite);                 
  54.                 sprite.graphics.beginFill(0xff0000);     
  55.                 sprite.graphics.drawRect(0+i/50,0,100,100);           
  56.                 sprite.graphics.endFill();            
  57.                 parentContainer.addChild(sprite);            
  58.             }         
  59.         }          
  60.         /** 
  61.          * 移除全部子元素  
  62.          *  
  63.          */  
  64.         private function removeAllChildrens():void{      
  65.             for(var i:int=0;i<num;i++){               
  66.                 parentContainer.removeChild(childrenRect[i]);                
  67.                 delete childrenRect[i];  
  68.             }      
  69.         }          
  70.         /** 
  71.          * 強制垃圾回收   
  72.          *  
  73.          */  
  74.         private function doGc():void{         
  75.             try{               
  76.                 var conn1:LocalConnection= new LocalConnection();                 
  77.                 conn1.connect("testGc");         
  78.                 var conn2:LocalConnection= new LocalConnection();              
  79.                 conn2.connect("testGc");         
  80.             }catch(error:Error){  
  81.                 conn1 = null;           
  82.                 conn2 = null;     
  83.             }            
  84.         }      
  85.     }  
  86. }  

 

   第一種狀況,不設置不用元素爲null和強制垃圾回收動畫

  

  

Java代碼   收藏代碼
  1.                             private function init() : void{    
  2. parentContainer=new Sprite();  
  3. addChild(parentContainer);   
  4. createAllChildrens();  
  5. removeAllchildrens();  
  6. //setChildrenNull();  
  7. //doGc();  

 

測試結果以下:spa

 

  

 

能夠看出佔用的內存比較高,點擊GC按鈕內存依然是「居高不下」。

 

第二種狀況,設置不用元素爲null但不強制執行垃圾回收。

 

Java代碼   收藏代碼
  1.                             private function init() : void{    
  2. parentContainer=new Sprite();  
  3. addChild(parentContainer);   
  4. createAllChildrens();  
  5. removeAllchildrens();  
  6. setChildrenNull();  
  7. //doGc();  

 

測試結果以下:

 

 

 

設置null後雖然剛開始峯值很高,可是Flash Player執行了垃圾回收,很快內存降低到12K。

 

 

第三種狀況,設置不用對象爲null並強制進行垃圾回收。

Java代碼   收藏代碼
  1.           private function init() : void{    
  2. parentContainer=new Sprite();  
  3. addChild(parentContainer);   
  4. createAllChildrens();  
  5. removeAllchildrens();  
  6. setChildrenNull();  
  7. doGc();  

 

 

測試結果以下:

 

  

 

 

能夠看出強制垃圾回收確實執行了。

 

 

 

內存泄露舉例:
一、引用泄露:對子對象的引用,外部對本對象或子對象的引用都須要置null。
二、系統類泄露:使用了系統類而忘記 作刪除操做了,如 BindingUtils.bindSetter(),ChangeWatcher.watch()函數時候完畢後須要調用 ChangeWatcher.unwatch()函數來清除引用 ,不然使用此函數的對象將不會被刪除; 相似的還有MUSIC,VIDEO,IMAGE,TIMER,EVENT,BINDING等。
三、效果泄露:當對組件應用效果Effect的時候,當本對象本刪除時須要把本對象和子對象上的Effect動畫中止掉,而後把Effect的target對象置null; 若是不中止掉動畫直接把 Effect置null將不能正常移除對象。
四、SWF泄露:要徹底刪除一個SWF要調用它的unload()方法而且把對象置null。
五、圖片泄露:當Image對象使用完畢後要把source置null。
六、聲音、視頻泄露: 當不須要一個音樂或視頻是須要中止音樂,刪除對象,引用置null。


內存泄露解決方法:
1. 在組件的REMOVED_FROM_STAGE事件回掉中作垃圾處理操做(移除全部對外引用(不論是VO仍是組件的都須要刪除),刪除監聽器,調用系統類 的清除方法) 先remove再置null, 確保被remove或者removeAll後的對象在外部的引用所有釋放乾淨。
2. 利用Flex的性能優化工具Profile來對項目進程進行監控,可知道歷史建立過哪些對象,目前有哪些對象沒有被刪除,建立的數量,佔用的內存比例和用量,建立過程等信息。

   
總結:關鍵仍是要作好清除工做,本身設置的引用本身要記得刪除,本身用過的系統類要記得作好回收處理工做。 以上問題解決的好的話不須要自定義強制回收器也有可能被系統正常的自動回收掉。

相關文章
相關標籤/搜索