Flash AS3,垃圾收集和带侦听器的多级精灵

Flash AS3,垃圾收集和带侦听器的多级精灵,flash,actionscript-3,garbage-collection,Flash,Actionscript 3,Garbage Collection,全部, 如果我创建一个精灵,并且该精灵包含许多子精灵(它们本身也包含子精灵),我需要担心垃圾收集所有东西,还是只收集父精灵?如果子精灵或孙子精灵附加了侦听器怎么办 例如,假设我有一个类(精灵的子类),它在应用程序中创建屏幕 该屏幕包含许多用于屏幕上所有UI功能的精灵(例如按钮、下拉菜单、文本字段等)。许多精灵上都有事件侦听器 因此,在我的申请中,我有: var myscreen:MyScreenClass = new MyScreenClass(); this.addChild(myscreen

全部,

如果我创建一个精灵,并且该精灵包含许多子精灵(它们本身也包含子精灵),我需要担心垃圾收集所有东西,还是只收集父精灵?如果子精灵或孙子精灵附加了侦听器怎么办

例如,假设我有一个类(精灵的子类),它在应用程序中创建屏幕

该屏幕包含许多用于屏幕上所有UI功能的精灵(例如按钮、下拉菜单、文本字段等)。许多精灵上都有事件侦听器

因此,在我的申请中,我有:

var myscreen:MyScreenClass = new MyScreenClass();
this.addChild(myscreen);
稍后,当用户完成该屏幕时,我将其删除:

this.removeChild(myscreen);
myscreen = null;
这就是我需要做的吗?或者,我是否需要递归地浏览myscreen,删除它的所有子精灵和事件侦听器

换句话说,如果你是一位家长,那么所有的孩子、孙子、曾孙等等都是GC'ed吗

(值得一提的是,我在事件侦听器中使用了弱引用…)


提前谢谢

是的,您甚至需要从子节点删除所有侦听器

编辑:

请特别阅读以下内容:


如果删除对父对象的所有引用,则无需删除其子对象或子对象的侦听器,前提是没有对子对象的外部引用

标记扫描垃圾收集器通过遍历对象图来工作,从最顶端的对象(即Stage)开始。剪掉图的一部分的所有路径,整个子图都可以被收集,而不管子图本身有任何引用

首先,让我们考虑一个没有事件的显示列表层次结构:

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
引用的所有引用,因此无法访问它,因此它将被垃圾收集。因此,没有必要
删除child
子体片段。只需确保清除对它们的任何外部引用(在本例中,
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
从clip引用到root,从clip2引用到root。当垃圾收集发生时,标记不能从根跳到片段,即使侦听器在那里。引用正在从剪辑到根的其他方向!因此,对象仍将被垃圾收集。因此,在这种情况下,没有必要删除侦听器。也就是说,如果你不确定的话,这样做没有什么坏处

侦听器防止垃圾回收的唯一方法是,如果子剪辑正在侦听父剪辑:

// from inside clip
root.addEventListener(MouseEvent.CLICK, someHandler);
此侦听器创建从根到剪辑的引用,因此必须删除该引用或使用弱引用。因为您使用的是弱引用,所以也不必担心这一点

这确实是一个需要跟踪的问题,而且很容易出错,因此在处理完侦听器后删除它们是一个很好的做法。如果你移除它们,你将永远安全。对于Flash为您发送的怪异本机事件,例如Event.ENTER_FRAME和KeyboardEvent.KEY_DOWN,这一点非常重要,但这并不是因为垃圾收集问题:即使剪辑没有引用并且符合收集条件,它将继续接收ENTER_FRAME事件,直到垃圾收集器在将来的某个不确定点实际运行为止。因此,您应该始终删除输入帧侦听器

但是在一个带有简单MouseEvents的小对象图的情况下,即使不麻烦删除侦听器,您也可以。它们不会伤害任何东西,并且当剪辑从显示列表中删除时,它们将不再被调度。您只需
removeChild
删除父剪辑即可


如果您想了解正在发生的事情,可以使用FlashBuilder、FlashDevelop或FDT中的探查器工具查看内存使用情况。您还可以使用
System.gc()调用强制GC在调试模式下运行。

你必须删除所有子项的所有侦听器。即使父项设置为null,侦听器仍然存在。