在AS3中如何强制进行垃圾回收?

18

在ActionScript 3.0中,是否可以编程方式强制运行完整的垃圾回收?

假设我已经创建了一堆带有事件监听器的显示对象(Display objects),其中一些显示对象已被删除,一些事件监听器已被触发和删除等等... 是否有一种方法可以强制运行垃圾回收,并收集所有可回收的内容?

8个回答

25

是的,这是可能的,但通常不是一个好主意。垃圾回收器应该比你更清楚何时运行是一个好时机,除非有一个非常特定的情况,比如你刚使用了500MB的内存并且需要尽快获得回收,否则就不应该自己调用垃圾回收。

在Flash 10中,有一个System.gc()方法可以调用(但请不要,见上文)-请记住System.gc()仅适用于Flash player 10+的调试版本。

在Flash 9中,有一种不支持的方式可以通过奇怪的LocalConnection命令进行强制处理,但它可能不能在所有版本中工作。请参阅Grant Skinner的此文章


7
这是一个很好的答案,但是错过了一个非常重要的点。它只在调试播放器中起作用!System.gc() - 仅适用于Flash Player的调试器版本和AIR应用程序。在AIR应用程序中,System.gc()方法仅在运行在AIR Debug Launcher(ADL)中的内容或安装的应用程序中处于应用程序安全沙盒中的内容中启用。[http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/System.html#gc()] - Simon_Weaver
5
在Flash 11中,有一个名为System.pauseForGCIfCollectionImminent()的方法可供调用。它接受一个参数,以便您可以告诉GC收集需要多么迫在眉睫才能发生暂停。有关更多详细信息/链接,请参见下面我的答案。 - pnkfelix

15

现在有一个新的API,用于告诉垃圾回收器它可能是一个“相对不错的时刻”进行回收。

请参阅Adobe API文档中的System.pauseForGCIfCollectionImminent

还有这个来自Adobe博客文章的链接:Adobe blog post,介绍了该方法在Player 11版本推出后不久的情况。

该方法需要一个“即将发生”的参数;基本上,如果您真的希望收集器运行,则输入较低的数字(接近0.0),即使自上次收集以来没有太多活动(当前由分配的字节数测量),并且如果您只想在我们已经接近本来会发生回收的点时才暂停收集,则输入较大的数字(接近1.0)。

这里的动机是针对例如游戏中需要将GC发生的时间稍微偏移一点的情况,例如在游戏的关卡变化期间执行GC,而不是在玩家开始探索关卡两秒钟后执行GC。

一个非常重要的细节:这个新API支持Release和Debugger Flash Runtimes。这使它比调用System.gc()更加出色。


8
对于目前发布的所有版本,System.gc()只在Flash播放器的调试版本和AIR应用程序的调试环境(ADL)中有效。Flash Player 10 beta目前可以在所有版本中使用。
我同意Davr的观点,这是一个不好的做法。运行时通常比你更了解情况。
此外,垃圾回收器的具体工作方式是实现细节,可能会因Flash播放器版本的变化而发生变化。因此,今天表现良好的方法不能保证在未来仍然有效。

有一个特定的情况,我有一个DataCache类,它的工作方式是保留结果对象,当刷新/接收数据时发送更新事件。清除缓存的方式是我只需从中清除所有结果并发送事件,这会导致任何剩余的侦听器重新请求其数据。如果在发送刷新事件之前无法立即强制清除所有仍然悬挂等待GC的侦听器,则这些悬挂的侦听器将再次请求数据。 - FredV

3
我对那些说永远不应该手动进行垃圾回收的人有一点评论。我习惯于在C++中进行手动内存管理,并且我更喜欢sharedptr而不是GC,但无论如何。
有一种特殊情况,我找不到另一种解决方案,只能进行垃圾回收。请考虑以下情况:我有一个DataCache类,它的工作方式是为某些方法调用保留结果对象,当刷新/接收数据时发送更新事件。缓存刷新的方式是我只需清除其中所有的结果并发送事件,这会导致任何剩余的侦听器重新请求其数据,而超出范围的侦听器不应重新请求,这样就可以清除不需要的结果。但是,显然,如果我不能强制清除所有仍然悬空等待GC被立即清理的侦听器,然后再发送“再次请求数据”的事件,那么这些悬空的侦听器将不必要地重新请求数据。因此,由于我无法使用removeEventListener,因为AS3没有析构函数,我看不到另一个简单的解决方案,只能强制进行GC以确保没有悬空的侦听器了。
(编辑) 此外,对于在mxml中设置的绑定,例如(使用我的自定义DataCacher类处理remoteobj),我也无法使用removeEventListener。
<mx:DataGrid id="mygrid" dataProvider="{DataCacher.instance().result('method').data}" ... />

当包含此数据表格的弹出窗口关闭时,您会期望绑定关系被销毁。显然,它们一直存在。嗯,Flex不应该在对象被标记为GC并删除最后一个引用时销毁所有绑定关系(即事件侦听器)吗?这对我来说可能是解决问题的方法。

至少我认为是这样,我还是Flex的初学者,欢迎提出任何想法。


3

正如其他人所说:不要尝试手动进行垃圾回收,虽然有一些技巧,但并不安全。

当可能时,您应该尝试对对象进行回收 - 这将节省大量内存。

例如,这可以应用于BitmapData(清除和重用),粒子(从显示列表中删除并重用)等。


3
try {
    new LocalConnection().connect('foo');
    new LocalConnection().connect('foo');
} catch (e:*){
    trace("Forcing Garbage Collection :"+e.toString());
}

你能解释一下GC和它为什么会被强制的联系吗? - duTr

0

回收并不能真正地帮助。我使用了一个加载器,每500毫秒重复加载同一张jpg图片。任务管理器仍然报告内存不断增加。

这里有经过尝试和证明的解决方案。

http://simplistika.com/as3-garbage-collection/


0

如果必要的话,调用垃圾回收器可能会很有用...所以,你必须小心地考虑何时以及如何进行操作,但毫无疑问,在某些情况下是必要的。

例如,如果您有一个模块化的应用程序,在从一个视图切换到另一个视图时,所有已删除的对象可能代表应尽快可用的大量内存,您只需要控制正在处理的变量和引用即可。


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