首页 > 解决方案 > 在 AS3 中,从阶段中删除子节点是否会删除对它的所有引用,以便垃圾收集器可以清理它?

问题描述

我正在创建一个 AIR 应用程序,该应用程序具有一个主类,该类创建大量影片剪辑实例并将它们添加到容器中。在整个应用程序的使用过程中,这些剪辑经常被销毁并创建新的。

当我创建这些影片剪辑时,我的主类会向它们添加事件侦听器。影片剪辑本身也有事件侦听器。

每当我更新显示时,我都会使用以下函数从其容器中删除所有这些影片剪辑:

        for (var i = 0; i < this.mainContainer.numChildren; i++) 
        {
            mainContainer.removeChild(mainContainer.getChildAt(i));
            //mainContainer.getChildAt(i)=null;
        }

我想知道这是否足以为垃圾收集准备这些实例,即这是否会杀死我的主类添加的事件侦听器?还是在删除每个孩子之前我需要先检查并删除事件侦听器?

此外,将每个实例归零在哪里适合这个?上面注释掉的行给出了错误:

1105: Target of assignment must be a reference value.

谢谢

标签: actionscript-3nullgarbage-collectionremovechild

解决方案


删除所有孩子

您的脚本不会删除mainContainer的所有子项,而只会删除一半。为什么?因为每次删除一个孩子时,其余部分都会关闭以消耗释放的索引,因此您的脚本将它们删除如下:

Initial picture  :  0 1 2 3 4 5 6 7 8 9
Remove child at 0:  1 2 3 4 5 6 7 8 9
Remove child at 1:  1 3 4 5 6 7 8 9
Remove child at 2:  1 3 5 6 7 8 9
Remove child at 3:  1 3 5 7 8 9

从给定容器中删除所有子项的正确方法是在给定时刻删除最后一个子项的反向循环:

for (var i = mainContainer.numChildren - 1; i >= 0; i--) 
{
    mainContainer.removeChildAt(i);
}

或者一个while循环,在深度 0 处删除子级,而有任何子级:

while (mainContainer.numChildren > 0)
{
    mainContainer.removeChildAt(0);
}

但是,有一种更简单的清空容器的方法(可从 Flash Player 11 及更高版本获得):

mainContainer.removeChildren();

垃圾收集器

对于 GC,一般的想法是没有从应用程序范围(附加到阶段和静态类成员的东西)到这些对象的有效引用。

如果您确定范围内没有任何内容引用它们或订阅它们,那么 GC 将正确完成其工作。

就我个人而言,我总是编写一个名为destroy(...)的方法,该方法会拆除给定对象中的所有内容:取消订阅所有事件侦听器,将Array的长度设为 0,将null分配给每个Object类型的变量,删除子级等.

我也同意Jyreel的观点,依靠显示容器为你保存东西不是程序员做事的方式,而是使用这种方式,或者设计更复杂的数据结构,这个决定取决于你和你的理解。


推荐阅读