谈谈actionscript垃圾回收

上传人:wm****3 文档编号:41641247 上传时间:2018-05-30 格式:DOC 页数:13 大小:592.50KB
返回 下载 相关 举报
谈谈actionscript垃圾回收_第1页
第1页 / 共13页
谈谈actionscript垃圾回收_第2页
第2页 / 共13页
谈谈actionscript垃圾回收_第3页
第3页 / 共13页
谈谈actionscript垃圾回收_第4页
第4页 / 共13页
谈谈actionscript垃圾回收_第5页
第5页 / 共13页
点击查看更多>>
资源描述

《谈谈actionscript垃圾回收》由会员分享,可在线阅读,更多相关《谈谈actionscript垃圾回收(13页珍藏版)》请在金锄头文库上搜索。

1、在给 AS 程序员的一点建议一文中我提到了释放资源的重要性。最近在一些 项目过程中我又对这方面有了更多的理解,在此希望能够分享给大家。首先让 我们来回顾一下关于垃圾回收(Garbage Collection,下文简称 GC)的一些知 识。要阅读本文,你需要对 GC 机制有些基本认识。在 ActionScript 中,我们没有 API 可以直接删除一个对象,也不能控制 Player 进行 GC。但是 GC 的行为是可以预估的,作为开发者,我们需要了解的 是 GC 执行的时机是发生在需要向操作系统请求分配内存的时候。从上面的模拟图我们可以看到:Player 以块的方式请求和释放内存。GC 的结果不

2、一定就是更少的内存占 用,也有可能是从操作系统获得更多的可用内存。 Player 会在某些 GC 过程中把内存中未使用部分组合成可以释放的块还 给操作系统。 此外还要注意的是 Player 为了避免占用太多的 CPU 资源,会将一些 GC 操作分到不同的时间片中运行,所以一次 GC 过程并不一定清理完所有可 回收资源。 一次 GC 过程(GC Pass)分为以下两个步骤:ReferenceReference CountingCounting统计所有对象的引用计数,如果某个对象没有任何引用,就标记为可回收。这个操作很好理解,需要强调的是 weak reference(弱引用)是不参与计算的。 引

3、用计数是一个相对省 CPU 的操作,能够筛选出大部分可回收资源,但是对一 些循环引用循环引用的情况就无能为力了。在下图中,标记为绿色的对象每个的引用数 都为 1,但它们明显是应该被回收的。所以 GC 需要进行第二个步骤:MarkMark SweepingSweeping这个步骤是从根对象(Root)开始轮询对象的引用。所谓的根对象包括:Stage 对象 静态变量 局部变量 这种方式足够精确,能够成功筛选出上图中绿色标记的对象,而它的代价就是 较大的计算开销。为了帮助 GC 过程更高效的执行,最好是能在第一步引用计数中就把需要回收的 对象都标记出来。具体的做法就是把所有不需要的对象引用全部清空不

4、需要的对象引用全部清空,包括:删除成员变量的引用 从可视对象列表上移除对象 移除事件监听 难点:事件监听是否会造成对象不能回收?这个问题要具体分析,有些情况可 以,有些情况却不可以。归根结底还是引用关系引用关系的问题。来看下面这个例子:Actionscript 代码 1. Foo.as: 2. 3. public class Foo extends Sprite 4. 5. private var bar:Sprite; 6. public function Foo() 7. 8. 9. /监听 bar 发出的事件。可以看作是 bar 引用了 foo,因为 foo 的引用被保存在 bar 的监

5、听者数组里。 10. bar.addEventListener(MouseEvent.CLICK, clickHandler); 11. addChild(bar); 12. 13. 14. private function clickHandler(event:MouseEvent):void 15. 16. . 17. 18. Actionscript 代码 1. Main.as: 2. 3. / 创建 foo 实例 4. var foo:Foo = new Foo(); 5. addChild(foo); 6. 7. / do something with foo. 8. 9. / 清除

6、 foo 的引用 10.removeChild(foo); 11.foo = null; 我们看到 foo 引用了 bar,而 bar 又通过事件监听的联系引用了 foo,这就构成 了一个循环引用。根据前文对 GC 步骤的分析,这两个对象都必须到第二步 mark and sweep 才能被标记出来。如果我们对事件监听用弱引用的方式:Actionscript 代码 1. bar.addEventListener(MouseEvent.CLICK, clickHandler, false, 0, true); 由于弱引用不计入引用计数,所以现在 foo 的引用数为 0。GC 在第一步操作中 就能把

7、 foo 标记出来,从而减少了一些运算开销。这也是为什么 Grant Skinner 呼吁把弱引用作为事件监听的默认方式的原因。但是作为最佳实践,我们还是提倡要手动移除事件监听移除事件监听。以下代码添加一个 destroy()方法(也有习惯命名为 dispose()或 kill()等)到 Foo 对象中:Actionscript 代码 1. public function destroy():void 2. 3. bar.removeEventListener(MouseEvent.CLICK, clickHandler); 4. removeChild(bar); 5. bar = null

8、; 6. 在清除 foo 的引用之前执行 destroy()方法:Actionscript 代码 1. foo.destroy(); 2. removeChild(foo); 3. foo = null; 经过我们如此处理,两个对象的引用数全都为 0。GC 只需第一步处理就完成任 务,我们节约了更多的运算开销!从上例可以看出在一般情况下,监听子对象的事件不会影响 GC。不管是弱引用 方式的监听,还是显式移除监听,都只是帮助 GC 更高效运行的手段,而不会影 响 GC 的结果。但是如果事件监听造成的是对象以外的引用关系,情况就不同了, 并且很有可能造成回收失败。一个常见的错误例子是监听 Stag

9、e 对象的 RESIZE 事件,如果没有显式移除这个监听或者是没有采用弱引用方式,那么这个对象 就不会被 GC 回收的。所以我建议大家还是要尽可能的显式移除监听,切断引用 关系。我们现在已经用对 GC 最友好的方式做好了清理准备,但是对象还没有从内存中 删除。在等待 GC 执行的这段时间,对象内的代码还在继续执行。比如加在对象 上的 ENTER_FRAME 事件监听处理还在继续执行,对象内的 MovieClip 或 Sound都还在继续播放。我们一定要避免这种情况的发生,所以在切断引用之前,我 们还要在 destroy()方法中做些清理工作。我们要做的工作包括:clearInterval(),

10、clearTimeout() timer.stop() loader.unload()/loader.unloadAndStop() movieclip.stop() 如果有子 MC 的,也要停止播放 bitmapData.dispose() 关闭 LocalConnection,NetConnection,NetStream 停止音频和视频的播放 删除 Camera 和 Microphone 对象的引用 调用子对象的 destroy()方法,如果有的话 其实这些都是在开发中管理资源的基本常识,归结为一句话就是:谁创建了对谁创建了对 象,谁就要负责清理该对象。象,谁就要负责清理该对象。下面就以

11、一些我在实际项目中开发的 destroy()方法为例,看代码说话:Actionscript 代码 1. public function destroy():void 2. 3. / List 是一个继承自 Sprite 的自定义子类 4. 5. / 移除 list 的事件监听 6. list.removeEventListener.remove(MouseEvent.CLICK, clickHand ler); 7. 8. / 我们创建了 list 实例,也要负责清理 9. / 调用 list 对象自己的 destroy()方法 10. list.destroy(); 11. 12. / 将

12、list 从显示列表移除 13. / 这一步并非必须的步骤,原因是 list 的父对象会被移除,这样 list 和 stage 就没有联系了。 14. / 但是在我的代码中,list 还有可能会被添加到外部的容器中 (比如 stage),那么这一步就是必须的了。 15. list.parent.removeChild(list); 16. list = null; 17. 18. / - 19. / loader 是一个来自 tweenmax 类库中的 ImageLoader 实例 20. 21. / 如果 loader 已经创建 22. if(loader) 23. 24. / 调用 loa

13、der 的 dispose()方法,优秀的第三方类库都应该 有良好的资源管理机制。 25. / 参数 true 表示把加载的内容从显示列表上移除,帮我们节 约了代码。 26. loader.dispose(true); 27. loader = null; 28. 29. 30. / - 31. / lightbox 实例变量保存了一个外部引用 32. / 根据谁创建谁清理的原则,我们在这里不需要负责该对象的清理, 只要删除引用就可以了。 33. lightbox = null; 34. 另一个示例的 destroy()方法演示了对数组中对象的处理方法:Actionscript 代码 1. p

14、ublic function destroy():void 2. 3. / cells 是一个数组,包含了一组子对象 4. var i : int, n : int; 5. n = cells.length; 6. for(i = 0; i = 0; i-) 3. 4. if(this.getChildAt(i) is IDestroyable) 5. 6. IDestroyable(this.getChildAt(i).destroy(); 7. this.removeChildAt(i); 8. 9. 总结:GC 好比是 ActionScript 城市的环卫工人,我们的每个类都是从事劳动 生产的市民。优秀的市民会把生产垃圾分类安放到回收点,而不文明的市民则 把垃圾丢得到处都是。你说哪种做法让城市的清扫工作变得更加高效?所以请 大家谨记“谁创建谁清理”的原则,做一位 ActionScript 好市民。上文中我们介绍了 GC 的工作机制和帮助 GC 更好工作的最佳实践。其实只 要我们遵守谁创建谁清理的原则来管理对象,就能基本上避免回收失败,也就 是我们通常说的内存泄漏问题。但是在实际项目中我们还会看到各种原因引起

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 社会民生

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号