[翻译]理解AS3的垃圾回收机制(下)
原文链接:http://active.tutsplus.com/tutorials/workflow/quick-tip-understanding-garbage-collection-in-as3/
难度: 中等
项目: Flash Develop, Flex Compiler
预计完成时间: 45分钟
第五步 创建另一个引用
现在我们证明了GC如我们预想中一般的执行了。我们换点别的:给对象另一个引用(Object1),然后移除本体。首先,我们要创建一个方法来建立和移除对象的引用连接,如下:
private function saveObject1(e:MouseEvent):void { // _onSave is a Boolean to check if we should link or unlink the reference if (_onSave) { // If there is no object to save, do nothing if (!_theObject1) { // Displays a text in the screen displayText("There is no object 1 to save!"); return; } // A new variable to hold another reference to Object1 _theSavedObject = _theObject1; // Displays a text in the screen displayText("Saved object 1 successfully!"); // On the next time this function runs, unlink it, since we just linked _onSave = false; } else { // Removing the reference to it _theSavedObject = null; // Displays a text in the screen displayText("Unsaved object 1 successfully!"); // On the next time this function runs, link it, since we just unlinked _onSave = true; } }
现在,测试我们的SWF。我们将发现,如果我们创建Object1,然后保存之,删除之,然后强制GC执行,神马都没改变。因为现在,即使我们一处了对象“原本”的引用,他还有另一个引用,这个使他不可回收。这是你所需要知道的基本的GC知识。这不是什么秘密。但是,我们应当如何将这些引用到我们的真实环境当中来呢?我们如何应用这些知识预防我们的应用变得更慢呢?这就是第六步将要涉及的知识。
第六步 有效的标称
现在到了最佳的部分了:让你的代码与GC无间合作。这一步将提供使你受益终生的信息。
首先,我将介绍一个新的方法用于在应用里创建对象,他是一个非常简单,但是与GC合作有效的方法。这个方法引入了两个简单的类。当你明白了他们是做什么的滞后,你就可以用他来扩展其他的。这个方法是在每个对象上实现一个叫做destroy的方法,然后每次你使用完之后就调用之。这个方法包含了需要移除所有引用到和引用自本对象的所有引用的代码(排除调用这个引用的方法的引用)。这样你可以确保对象与你的应用是隔离开来的。他可以很清楚的被GC所识别,这样做的原因会在下一步里面解释,我们先看看代码:
// Create this in every object you use public function destroy():void { // Remove event listeners // Remove anything in the display list // Clear the references to other objects, so it gets totally isolated } // ... // When you want to remove the object, do this: theObject.destroy(); // And then null the last reference to it theObject = null;
在这个方法里头,你需要需要从对象里面清理所有的东西。这样让应用隔离开来。做完这些之后,可以让GC很容易定位和移除此对象。现在我们看看内存错误经常发生的一些情况:
1 对象只在一个执行时间段里存在,然后它们不是经常被访问到。记得在用完之后移除他们的引用。否则,应用里面就会有一堆这样的东西。它们占着茅坑不拉屎。记住,你必须通过destroy()方法来排除他们。
2 显示列表里面残留的对象:记住,删除一个对象一定要先把它从显示列表删除。显示列表页是GC根之一(记得否?)。所以移除它们的时候千万记得把他们从显示列表中隔离开来。
3 stage,parent和root引用:如果你喜欢使用这样的引用,记得在用完后移除之。如果你很多对象有这样的引用,恭喜你,你麻烦大了。
4 事件监听器:有时候让你的对象排除于了GC之外的原因是一个小小的事件监听器。记得移除他们,如果可以的话,你可以用弱引用。
5 Array与Vector: 有时候Array和Vector里面可能有其他对象或者残留的引用,而你不知道。所以小心Array和Vector的使用。
第七步 引用之岛
尽管GC很好,但是也不是尽善尽美的。你需要小心从事。否则,将会有麻烦接踵而至。我将证明当你不遵循要求的步骤让你的代码恰当的与GC写作将会发生什么问题。
有的时候,当你不清除所有引用到和引用自本对象的引用的时候,你可能有这样的问题存在,特别是当你的应用里有一堆的引用对象的时候。有时候,一个残留的引用足以至此。所有你的来自引用之岛的对象,由于相互之间的引用,会阻止GC回收它们。
当GC执行的时候,他执行两个简单的任务以检查需要移除的对象。第一项任务是计算每个对象本身有多少引用,所有0引用的对象同时搜集,另一项任务是检查时候有一小撮对象相互之间引用,但是无法访问,因此浪费了内存,如下图:
如你所见,那一堆绿色的对象无法访问。但是他们的引用为1.GC执行第二项任务的时候查到了这一堆对象并移除他们。尽管如此,当这个堆太大的时候,GC会放弃检查,并认为他们是可以访问到的。现在想象一下,你有这么个东西:
这个就是引用之岛。它会占用很大的内存空间,且不能通过GC回收。因为他们太复杂了。听起来很糟糕,对吧?这个很容易去避免,只需要确保你清理了对象的引用与自引用。这样的话,这么恐怖的事情是不会发生在你身上的。
总结
在本文中,我们学到了如何让我们的代码编得更好更高效以减少延迟和内存事件的产生。因此,让它变得更稳定。做到这些,我们只需要知道as3中的引用对象是如何工作的,然后从中获益,然后可以让GC在我们的项目中更好的执行。因为我们可以将我们的项目做得更好,所以我们要小心从事,否则他会变得更慢更糟。
如果任何疑问,欢迎来此留言。
Thanks