2011-03-25 27 views
3

所有,AS3,垃圾收集和多層次的精靈與聽衆

我如果創建一個精靈,而精靈包含許多子Sprite(其本身也包含子精靈),做我需要擔心garbage-收集一切,或只是父母精靈?如果孩子或孫輩的小精靈有聽衆呢?

例如,假設我有一個類(一個Sprite的子類),它在應用程序中創建一個屏幕。

該屏幕包含許多用於屏幕上UI可用性的Sprites(例如,按鈕,下拉菜單,文本框等)。許多精靈都在其上有事件監聽器。

所以,在我的申請,我有這樣的:

var myscreen:MyScreenClass = new MyScreenClass(); 
this.addChild(myscreen); 

後來,當用戶與屏幕做,我將其刪除:

this.removeChild(myscreen); 
myscreen = null; 

是所有我需要做的?或者,我是否需要通過myscreen遞歸去除所有它的子Sprites和Event Listeners?

換句話說,如果你是一位父母,那麼所有的孩子,孫輩,曾孫,等等也是GC?

(對於它的價值,我使用弱引用在我的事件監聽器......)

提前感謝!

+1

你必須刪除所有孩子的所有聽衆。即使父級設置爲空,偵聽器仍然存在。 – jpea 2011-03-25 18:07:18

回答

10

如果您刪除對父對象的所有引用,則不需要刪除其子對象或對子對象的偵聽器(假設沒有對子對象的外部引用)。

標記清除垃圾回收器通過遍歷對象圖從最頂層的對象(即舞臺)開始工作。將所有路徑剪除到圖的一部分中,並且整個子圖將有資格收集,而不管子圖之間有任何引用。

首先,讓我們考慮只是一個顯示列表層次結構,而不事件:

var clip:Sprite = new Sprite(); 
addChild(clip); 
var clip2 = new Sprite(); 
clip.addChild(clip2); 
// cleanup 
removeChild(clip); 
clip = null; 
clip2 = null; 

內孩子CLIP2會被垃圾收集,即使我們沒有通過clip.removeChild(clip2)從其父將其刪除。由於我們刪除了所有對父代clip的引用和明確的clip2引用,因此無法訪問它,因此它將被垃圾收集。因此,沒有必要removeChild後代剪輯。只要確保你清除任何外部引用(在這種情況下,clip2)。

現在讓我們想象一些事件:

var clip:Sprite = new Sprite(); 
addChild(clip); 
clip.addEventListener(MouseEvent.CLICK, someListener); 
var clip2:Sprite = new Sprite(); 
clip.addChild(clip2); 
clip2.addEventListener(MouseEvent.CLICK, someOtherListener); 
// cleanup -- the same! 
removeChild(clip); 
clip = null; 
clip2 = null; 

你可能會認爲你必須刪除事件偵聽器,但它實際上是沒有必要的。 addEventListener創建從調度程序到偵聽器的引用。也就是說,將偵聽器添加到子對象不會阻止其垃圾收集。在這種情況下,addEventListener將剪輯引用到root,將clip2引用到root。發生垃圾回收時,即使該偵聽器在那裏,標記也不能從根節點跳轉到剪輯。參考是其他方向,從剪輯到根!所以對象仍然會被垃圾收集。因此,在這種情況下,不必刪除監聽器。也就是說,如果你不確定,這並不會傷害你。

的唯一途徑聽衆可以防止垃圾回收是,如果一個孩子夾在聽父剪輯:

// from inside clip 
root.addEventListener(MouseEvent.CLICK, someHandler); 

此偵聽器創建一個從根參考夾,所以您必須刪除引用或使用弱引用。既然你使用的是弱引用,你也不必擔心。

確實需要跟蹤很多事情,並且很容易犯錯,所以最好是在您完成對話時刪除聽衆。如果你刪除它們,你將永遠安全。這對於Flash爲您調度的奇怪本地事件非常重要,如Event.ENTER_FRAME和KeyboardEvent.KEY_DOWN,但不是因爲垃圾回收問題:即使剪輯沒有引用並且有資格收集,它仍會繼續接收ENTER_FRAME事件,直到垃圾收集器實際運行在未來的某個不確定點。所以你應該總是刪除ENTER_FRAME監聽器。

但是在使用簡單MouseEvent的小對象圖的情況下,即使您不打擾刪除偵聽器,您也可以。他們不會傷害任何東西,當剪輯從顯示列表中刪除時,他們將不再被分派。你可以只用removeChild父剪輯並完成它。

如果您想查看正在發生的事情,在Flash Builder,FlashDevelop或FDT中使用Profiler工具查看內存使用情況會很有幫助。如果您想測試這些想法,您也可以使用System.gc();調用來強制GC以調試模式運行。