每次您使用“new”关键字创建对象时,您都在将自己的主张押注在一块内存上 [1]。因此,假设您通过编写 var exampleUint:uint = new uint(); 来创建一个 uint。 ActionScript 对计算机说“嘿......我需要......四个字节的内存。”,计算机回复“好的,酷,使用从 [某个内存地址,如 0x7B3208C1] 开始的四个字节”[2] .所以当你说var someString:String = "blah";你在内存中声明一个空间,用一些信息填充它(在这种情况下,它是"blah"),创建一个标签(在这种情况下,它是someString)和bind标签到内存中的那个空间。
现在标签实际上并不与数据本身相关联,它与内存中包含数据的位置相关联。这似乎令人困惑,因为它确实如此,但由于某些原因,它有很大的意义。 ActionScript 中的所有对象都是reference 类型,这意味着该对象包含一些数据的内存地址,而不是数据本身。这与 value 类型的对象形成对比,其中标签与数据本身相关联。不要担心值类型的细节,因为它不在 ActionScript 中,所以出于您的目的,我将它严格包含在内以进行对比。好吧,糊涂了?您可能应该这样做,因为这整个段落是不必要的,甚至可能是不必要的,但请尽量将其放在脑后,因为它可能与您的问题有关。
现在,当该标签消失时(例如,它从 scope 中消失,所以现在 someString 没有意义),只有标签 someString 被删除。所以对于这个例子,如果你说someString = null;,字符串"blah"实际上还在内存中,但是标签someString没有引用那条信息,它引用了the null object的内存地址(再次,细节)。我们需要一种方法来向计算机指定“你知道我声称从 [whateverAddress] 开始的 [whateverSize] 内存块吗?好吧,我现在已经完成了,所以其他人可以使用那块内存”。 Gabage collection 是一个自动回收您已声明的内存的过程,而不必自己担心。在没有垃圾收集的语言中,new 有一个补充关键字,专门释放与对象关联的内存 [3],但 ActionScript 没有。你只需记住一段记忆,然后忘记它。
在某个地方,您可能已经创建了另一个变量并引用了那条数据,var someOtherString:String = someString;,所以我们不能只说“好吧,标签someString 不见了,所以让我们摆脱数据它引用”,因为我们不确定someString 是对该数据的唯一引用。完成此操作的方法因语言和垃圾收集系统而异,但 ActionScript 中的基本处理是:每隔一段时间(特别是如果 Flash 当前占用大量内存),垃圾收集器会查看所有当前 SWF 中的对象并查找所有没有任何引用的对象 [4]。因此,对于我们之前的示例,如果 someString 是唯一引用字符串 "blah" 并且 someString 超出范围的对象,则 "blah" 不与任何标签关联,因此 Flash 完全无法访问。下次垃圾收集器运行时,它会找到它,然后向系统报告它已经完成了那块内存。
现在,如果不查看源代码,很难说出您的特定问题的具体细节,但我可以告诉您,经常导致问题的一件事是事件侦听器。有时您可能会创建一个函数并将其添加为事件侦听器。现在事件本身有对该函数的引用 [5],所以如果函数超出范围,仍然有对它的引用,并且该函数不会被垃圾收集器拾取(记住, 函数是 ActionScript 中的对象)。您可以通过调用 removeEventListener 手动删除事件处理程序(我不推荐它),或者将调用中的 useWeakReference 参数设置为 addEventListener() 到 true。垃圾收集器无法识别弱引用,因此将 useWeakReference 设置为 true 可以防止您有一个函数应该被垃圾收集器拾取,但它没有因为有人将它引用为事件侦听器。从项目中 mouseEvent 侦听器的绝对数量来看,这可能是罪魁祸首。如果你有 Flex Builder,你可以使用分析器查看你有多少方法闭包;如果他们上升并且永远不会下降,那可能是你的问题。
[1]:请记住,这也适用于您在不使用 new 关键字的情况下创建对象的情况,例如您要编写 var exampleInt:int = 5;。
[2]:我选择 uint 是因为所有 uint 的大小都相同,所以我可以自信地说我知道它将是 4 个字节。字符串不同;它们占用的内存量与它们包含的字符数成正比,因此在这两个示例中都使用 String 会更加模棱两可。
[3]:ActionScript 关键字delete 不是用于此目的,因此不要尝试以这种方式使用它,即使这样会合乎逻辑并且非常有用。
[4]:Flash使用mark-and-sweep风格的策略,更具体的细节可以阅读here。
[5]:实际上,这是一个粗体的谎言,因为 addEventListener 方法使用了closures,但我对它的理解很薄弱,所以我不能把它归结为普通人的英语。