如何在Actionscript 3中删除/回收一个对象?

20
我想从类实例本身内部删除/强制进行垃圾回收。显然,this = nulldelete this 无法起作用。是否有任何方法可以实现这一点,或者我正在走错路线?我基本上在寻找某种析构函数。
我拥有一个类实例,试图加载一个XML文件,如果该文件未找到,我希望从其自身内部销毁该实例,最好的情况是这样做之后能够在父类中根据子实例是否为空执行一些操作。
我考虑过向父类抛出事件并从那里删除子实例,但如果没有其他方法,我更喜欢不这样做。
6个回答

22

不应该尝试从对象本身中删除对象,这是一种不良实践,在AS3中你肯定无法这样做。

仅当没有剩余引用指向一个对象时,该对象才可能被删除(即垃圾回收)。由于引用始终按值传递,并且通常对象无法知道哪些引用指向自己,因此你无法从对象本身中删除对象。唯一有用的方法是创建一个方法,将清理实例使用的所有资源。这个方法将充当一个析构函数,但你必须手动调用它。不要忘记事件监听器也会防止垃圾回收,除非你将它们删除。

删除属性和将其设置为null之间还有区别。实际上,delete将从动态类的实例中删除属性。而将属性值设置为null不会删除属性,但会删除存储在其中的任何引用。因此,这两种操作都会销毁存储在某个属性中的引用。请注意,你无法delete一个对象,只能删除属性。

在Flash Player 9和旧版本中,可以使用某些技巧来启动垃圾回收。然而,最近System.gc()调用已经可用,它可以完成相同的功能。请注意,你不能真正依赖于GC是否将被调用。这取决于Flash Player。

回到你的问题: 抛出事件并通知父级发生了错误实际上是个好主意。你应该坚持这个想法。此外,如果父节点知道这样的事件,而不是在其属性被神奇地置空时才发现,那么效果更好。

P.S.: 阅读Grant Skinner在Flash Player中关于内存的文章是一个好主意。 链接


请注意,您无法删除一个对象,只能删除一个属性。- 我不确定您的意思是什么。如果我的属性是一个对象怎么办? - Luke
2
@Luke:我的意思是,对象A的属性可能持有对某个对象B的引用,但delete A.prop只会删除该属性以及引用。也就是说,A将不再具有属性prop,但可能仍然存在对对象B的引用。因此,B将无法被垃圾回收。 - dragonfly
6
System.gc() 只能在 Flash Player 的调试版本中使用。您应该修改说明以明确指出它不应该用于除调试之外的任何其他目的。 - Jonathan Dumaine
@Jonathan Dumaine:感谢您的评论。然而,我认为“你无法真正依赖”部分清楚地暗示了System.gc()在生产代码中用途不大。此外,如果程序员不尝试咨询文档,导致的问题完全是他自己的责任。点赞你的评论来强调这个问题。 - dragonfly

5

如果使用addChild()方法将对象添加到DisplayContainer中,您可以通过使用parent.removeChild(this)从对象内部将对象从容器中移除。如果在此之后对该对象没有引用,则将由垃圾回收器处理。

唯一的问题是当您在对象内部有事件侦听器时,您可以手动删除它们或者通过在所有侦听器上设置weakReference=true让垃圾回收器为您处理。


1

仅对Flash Player调试器版本和AIR应用程序有效,对我几乎没有任何用处。 - evilpenguin

1
你应该先了解一下垃圾回收,Grant.S 写了一篇很好的文章介绍这个问题:

http://www.gskinner.com/blog/archives/2006/06/as3_resource_ma.html

重点不是将类本身设置为null,而是删除所有引用,包括监听器。一旦它完全孤立,垃圾回收器可能会在某个时候将其清除。
基本示例:
// References a newly created sprite
var reference:Sprite = new Sprite();

// Removes the reference, the Sprite is now orphaned and will probably be garbage collected within some seconds.
reference = null;

一个好的实践是在所有类上系统地创建一个“destruct”方法,以删除所有内部引用、处理位图、移除事件侦听器等,之后你只需要担心解除外部引用即可。
如果您使用FLEX Builder,则可以使用分析器来可视化Flash Player内部处理所有这些内容的方式。

1

这里有一种不受支持的方法可以从GSkinner强制进行垃圾回收。

try {
   new LocalConnection().connect('foo');
   new LocalConnection().connect('foo');
} catch (e:*) {}
// the GC will perform a full mark/sweep on the second call.

1

AS3没有提供析构函数。你能做的最好的事情就是将所有引用设置为null,然后祈祷垃圾回收器能够注意到并释放内存。


好的,但是我怎样可以在类实例内部将其设置为 null? - evilpenguin
@evilpenguin,除非你使用单例模式,否则你不应该在类内部这样做。你应该在实例化该类的类中进行操作。 - KingNestor
@evilpenguin:如建议所示,您必须从外部进行操作。 - dirkgently

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接