原文 Understanding garbage collection inFlashPlayer 9 翻译 目前我暂时在研究ActionScript3.0,它的能力让我很激动。它的原生执行速度带来诸多可能(此句原文The raw execution speed by itself provides so many possibilities. raw本意未加工,原始的,这里的意思是指引入AVM2之后,ActionScript3.0在执行速度上有了很大提高,所以使支持更复杂的组件成为可能,译者注)。它引入了E4X、sockets、byte 数组对象、新的显示列表模型、正则表达式、正式化的事件和错误模型以及其它特性,它是一个令人炫目的大杂烩。 巨大的能力意味着巨大的责任,这对ActionScript3.0来说一点没错。引入这些新控件带来一个副作用:垃圾收集器不再支持自动为你收集垃圾等假设。也就是说Flash开发者转到ActionScript3.0之后需要对关于垃圾收集如何工作以及如何编程使其工作更加有效具备较深入的理解。没有这方面的知识,即使创建一个看起来很简单的游戏或应用程序也会出现SWF文件内存泄露、耗光所有系统资源(CPU/内存)导致系统挂起甚至机器重启。 要理解如何优化你的ActionScript3.0代码,你首先要理解垃圾收集器如何在FlashPlayer 9中工作。Flash有两种方法来查找非活动对象并移除它们。本文解释这两种技术并描述它们如何影响你的代码。 本文结尾你会找到一个运行在FlashPlayer9中的垃圾收集器模拟程序,它生动演示了这里解释过的概念。 关于垃圾收集器 垃圾收集器是一个后台进程它负责回收程序中不再使用的对象占用的内存。非活动对象就是不再有任何其他活动对象引用 它。为便于理解这个概念,有一点非常重要,就是要意识到除了非原生类型(Boolean, String, Number, uint, int除外),你总是通过一个句柄访问对象,而非对象本身。当你删除一个变量其实就是删除一个引用,而非对象本身。 以下代码很容易说明这一点: ActionScript代码
- // create a new object, and put a reference to it in a:
- var a:Object = {foo:"bar"}
- // copy the reference to the object into b:
- var b:Object = a;
- // delete the reference to the object in a:
- delete(a);
- // check to see that the object is still referenced by b:
- trace(b.foo); // traces "bar", so the object still exists.
如果我改变上述示例代码将b也删除,它会使我创建的对象不再有活动引用并等待对垃圾收集器回收。ActionScript3.0 垃圾回收器使用两种方法定位无引用的对象 : 引用计数法和标识清除法。 引用计数法 引用计数法是一种用于跟踪活动对象的较为简单的方法,它从ActionScript1.0开始使用。当你创建一个指向某个对象的引用,该对象的引用计数器加1;当你删除该对象的一个引用,该计数器减1。当某对象的计数器变成0,该对象将被标记以便垃圾回收器回收。 这是一个例子: ActionScript代码
- var a:Object = {foo:"bar"}
- // the object now has a reference count of 1 (a)
- var b:Object = a;
- // now it has a reference count of 2 (a & b)
- delete(a);
- // back to 1 (b)
- delete(b);
- // the reference count down is now 0
- // the object can now be deallocated by the garbage collector
引 用计数法简单,它不会非CPU带来巨大的负担;多数情况下它工作正常。不幸地是,采用引用计数法的垃圾回收器在遇到循环引用时效率不高。循环引用是指对象 交叉引用(直接、或通过其他对象间接实现)的情况。即使应用程序不再引用该对象,它的引用计数器仍然大于0,因此垃圾收集器永远无法收集它们。下面的代码 演示循环引用是怎么回事: ActionScript代码
- var a:Object = {}
- // create a second object, and reference the first object:
- var b:Object = {foo:a};
- // make the first object reference the second as well:
- a.foo = b;
- // delete both active application references:
- delete(a);
- delete(b);