`
star65225692
  • 浏览: 273304 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类

AS3的垃圾回收

阅读更多

垃圾回收,这次是一个被无数人讨论过的传统话题。

Action Script使用的是和Java相似的内存管理机制,并不会即时回收废弃对象的内存,而是在特定时间统一执行一次GC(Gabage Collection)操作来释放废弃对象的内存,避免了重复判断是否需要回收产生的性能问题。

但要注意,这只是决定回收的时机,而不是回收的内容。这个延迟执行内存回收也就是个表面的现象,不管什么时候执行GC,能够回收的内存最终都能回 收,不能回收的肯定不能回收。唯一的影响是,因为回收是延迟执行的,你在查看内存的时候不能直观地看到因为一个对象被废弃而回收内存的过程,会产生迷惑。

但这对于解决内存泄露是无关紧要的。

内存泄露指的就是当你销毁了一个对象的时候,它占用的内存却无法被回收,这会导致可用内存越来越小最终溢出,在内存紧张的环境中将会造成系统崩溃。其原因多种多样,但一般都是开发者的疏忽所致,没有提供给系统足够的可以销毁对象的依据。Android应用排行榜

执行GC虽然和内存泄露没有关系,但是如果不在测试前执行GC,你将看不到当时实际的不可回收内存的量,而内存泄露就是指不可回收内存的数量的增 加。因此,测试内存回收将离不开GC方法。没有使用GC方法的测试用例是没有意义的,因为这其中掺杂了偶然性(什么时候执行GC)。不少荒谬的测试结果都 是因为没有在正确的位置执行GC导致的。

Flash Player虽然没有开放发布状态的手动gc,但调试版本是可以使用的,正好可以让我们测试。此外下面的HACK代码也可以在发布阶段触发GC。

try {
    new LocalConnection ().connect ( "gc" );
    new LocalConnection ().connect ( "gc" );
} catch ( e:Error ) {}

但我再次强调,调用GC仅仅是用于测试。实际产品中调用GC基本没有意义(除了用于控制GC时机),总之如果你的程序出现了内存泄露,那一定和GC没有关系,请不要再在这种地方浪费宝贵的时间与精力。

只有在申请内存时才会触发自动GC

AVM2的GC是在每次申请内存时,根据当前内存占用来触发的。申请内存是一个必要因素。所以,如果你一直不进行申请内存的操作,就算内存达到了一个高值,它也不会进行GC。

这确实是个不合理的地方。但是,在实际环境中,一直不请求内存的情况是很少见的,就算出现,当时也未必处于内存的高值。这种情况主要出现在测试环境中,导致一些人会怀疑自动GC的功能是否正常。实际上这也是没有必要的。

Flash中垃圾回收的条件

在AVM2中,除去特殊的BitmapData必须调用dispose才能回收内存外,其他的部分都是用引用计数法和标记清除法作为判断是否应该回收内存的手段,而且并没有提供主动回收的API,详细部分请看这篇日志,我就不重复了。

因此,你要回收一个对象,只要保证没有任何对象引用它,而且他的方法没有被当做事件函数——或者说,他和程序的其他部分已经没有任何联系,它就满足 了引用计数法的标准,就一定会被回收。做到这一点的方法就是一般说的“执行removeChild,removeEventListener,将对他的引 用设置为null”。

但是,实际上回收一个对象的要求并没有那样严格,就在于FP除了引用计数法,还包括标记清除法。标记清除法是从程序的根对象开始(stage,静态 属性,活动的定时器和加载器,ExternalInface.callBack)一级一级遍历对象,只要遍历不到,即使不满足引用计数法的条件也可以回 收。比如两个对象互相引用,但是和外界都没有关系,形成了孤岛,它们就可以被回收,尽管它们因为互相引用使得引用数不为0。比起单纯的引用计数,这种办法 能确实能找到已经无法再访问到的实际上的闲置对象。所以,可以看到很多人的代码实际上并没有设置null,甚至没有 removeEventListener,它一样可以被正常回收,少写这些代码可以使得程序更简洁,要全部符合标记清除法的条件,会很累。

“无法被根访问”,这种说法很暧昧,基本不能当做判断依据。所以我下面会举几个具体例子,来说明什么样的情况是符合标记清除法的要求的。坏账

首先明确一点,标记清除法是只以能否能被根访问作为唯一依据的,并不需要关注被引用的次数,请不要混淆。

  • 属性的相互引用是很明确的,一般都是一个对象包含着若干属性,那么这个对象自然可以维持它的属性的引用。如果这个类不会被回收(能够被根 访问),他的所有属性也都不会被回收。同样的,如果这个类可以被回收的话(不能被根访问),也就不会妨碍属性的回收。所以你并不需要将所有属性设置为 null,除非你希望在对象存在时候就回收其属性的内存,这种需求基本不存在。
  • 静态属性是一个特殊的情况。静态属性本身就是根,所以你必须将其设置null才有可能被回收,没有别的办法。
  • 至于在显示列表中的对象。既然根(stage)可以用getChildAt访问到自己的所有子对象,那么只要你在显示列表中,就肯定不会 被回收。然而,如果显示对象的父层对象已经不再显示列表内,它的子对象就算还在父层对象之中也没有关系,因为它已经不能被stage访问到了。所以你不需 要removeChild各层的全部对象,而只需要removeChild最高一层的父对象即可。
  • A.addEventListener(“event”,B.handler),像这样添加过事件后,你可以认为B.handler成为 了A的一个属性(因为A在需要的时候要能调用B.handler),这里也符合属性相互引用的原则。但是事件判断起来的确要比属性麻烦,因为相互引用的情 况很多。在这里可以分为三种情况:
    1. 对自己监听自己的事件,这相当于用自己的属性保存自己引用,任何情况都不会阻碍自己被回收。
    2. 对自己的子对象(属性或者child)监听自己的事件。因为子对象本来就是自己在维持它的引用,那么即使它们会维持你的引用,也 只会形成一个循环。一旦你和stage脱离了联系,子对象同样也会脱离联系,当然也无法妨碍你自己被回收了。除非子对象因为一些原因可以单独维持引用(诸 如被保存在静态属性中),但这种情况很少见。
    3. 对自己的父对象(parent或者stage)监听自己的事件。因为这使得你成为了父对象的一个属性,只要parent或者 stage不被回收,那么自己就不会被回收。尤其是stage,它肯定不会被回收。这种情况一般都会导致自己无法回收,是必须 removeEventListener的。

总得来说,就是务必注意对stage,parent的事件监听,其他情况一般都是不会妨碍回收的。而对stage,parent的监听大多都是各种鼠标,键盘事件。数量并不多,专门注意这里可以杜绝大部分因为事件造成的内存泄露。

其实,内存泄露并不容易出现。按照普通的编程习惯,只有监听stage事件这种做法会造成意料之外的泄露,一般都是可以顺利回收的。这比每次都要手工回收内存要方便多了。2011大智慧下载

这里只有BitmapData是例外。除了遵从上面的规则外,要回收它的内存,必须手动调用dispose方法,习惯自动回收的人会很累。务必注 意,Bitmap对象的bitmapData属性是需要手动销毁的,Loader加载的位图是需要手动销毁的,当你用一个生成的位图作为位图填充绘制平铺 的图像后,在销毁这个图像后也必须销毁这个位图(所以你必须一直保存位图的引用)。BitmapData是32位的未经任何压缩的图像,随便一个体积都会 非常大,不处理好它们的回收,一个BitmapData泄露就可以顶你数万个复杂对象的泄露。

如果出现非常明显的内存泄露,大部分时候都是位图泄露。所以在研究上面的引用计数法和标记清除法以及GC之前,请先保证位图部分不出问题。

弱引用时的例外

弱引用会改变垃圾回收的规则。如果使用了弱引用,addEventListener将不会影响对象回收,即使对stage添加监听,也不会导致自己 被回收。但是这同时也是缺点,因为有的时候你就是希望用引用限制住对象的回收,使用弱引用会使得这个对象有时回收有时不回收。虽然极少出现,但一旦出现, 这种不容易重现的错误是很难查出来的。因此我并不推荐使用弱引用。

弱引用在AVM2中只有两处:

  • 一处是addEventListener的第5个属性,名为userWeakReference,设置为true,监听事件将不会影响对象回收。
  • 一处是Dictionary的构造函数参数,名为weakKeys,设置为true,当键为复杂对象时,即使Dictionary存在,键依然可以被回收。注意,这里说的是键,不是值,值是不享受弱引用待遇的。这个属性也写得也很明白,是weakKeys。

 

必要时可以执行强制GC

因为每次GC都需要消耗性能,对象越多,GC越慢。我理解Flash Player禁用发布版本的System.gc()是为了避免开发者滥用这个方法,但有些时候我们的确需要手动控制GC时机,因为GC过程如果遇到大量可回收对象会让Flash Player卡住。

比如,我们需要在切换屏幕时回收一次内存,这时候卡是看不出来的,而不是切换完后播放动画时回收然后让动画顿住。或者,我们会定期在必要的时候执行 一次GC,将GC需要的时间分担开。所以这时候用HACK方法强制执行一次GC也不失为一个选择。当然,这和内存泄露半点关系都没有。

Flash Player这个地方的设计特别的不好。它自己又不支持分步GC,一旦GC的时候没有办法避免卡的问题。结果GC的时机还不给控制……

微量剩余内存

测试中FLASH的确存在微量内存无限增加的问题,原因未知。我将50万个对象扔在一个数组中,销毁后确实会多出1M的内存占用(如果没扔在数组中不会),但这个数量很小,但达到能看得出来的100M内存需要5000万个对象,这个数额在通常情况下很难达到。

不过也有人说这只是对象销毁而内存并未全部释放的表现,实际上最后还是能完全释放的。或者是因为totalMemory的不精确所造成的。这个我就不清楚了。

不过就算这个的确是FlashPlayer的BUG,也无伤大雅吧。

分享到:
评论

相关推荐

    最经常遇到的AS3面试题

    本文将对AS3面试中经常遇到的问题进行总结和解释,涵盖了动态加载资源、事件机制、数据类型、字符串处理、垃圾回收器、Flex与后台语言交互等多个方面的知识点。 1. Loader, URLLoader, URLStream的使用场合和区别 ...

    AS3内存优化及垃圾回收参照.pdf

    内存管理和垃圾回收是任何程序设计语言中的重要概念,AS3也不例外。在AS3中,内存优化和垃圾回收策略对性能有着显著影响,特别是在处理大量数据或者运行长时间的程序时。 1. **显示对象的选择**: - Shape对象适用...

    AS3内存优化及垃圾回收.pdf

    AS3没有类似Free的方法强制释放内存,只能依赖垃圾回收机制。 4. **BitmapData复用**:共享BitmapData实例可节省内存。多个bitmap可以共用同一BitmapData,避免频繁创建新实例。 5. **对象池技术**:重复使用相同...

    Flash强制垃圾内存回收测试

    在AS3中,垃圾回收算法通常采用分代收集的方式,将内存分为新生代和老年代,分别对待,以优化回收效率。 测试垃圾回收性能的方法包括但不限于: 1. **内存快照**:在运行前后获取内存使用情况,对比分析内存的变化...

    as3 loader资源的回收

    3. 将Loader的引用设置为null,以便垃圾回收机制可以回收Loader及其加载的资源: ```actionscript loader.unload(); loader = null; ``` 在AS3中,`unload()` 方法不仅从舞台中移除Loader的内容,还会释放...

    Flex面试题.pdf

    5. AS3垃圾回收: - 早期的引用计数法,后改为标记法,从根节点遍历所有引用并标记,未被标记的对象被视为可回收。 6. Flex与后台交互: - Remote Object:用于调用服务器端的远程服务,通常基于AMF协议,速度快...

    FlipPage-as3

    AS3允许开发者使用位图缓存技术提高渲染效率,同时合理地管理内存和垃圾回收,确保在保持效果的同时,程序运行流畅。 6. **自定义功能**:在“FlipPage-as3”项目中,可能还包含了对翻页速度、角度、页面材质等的...

    flashas3手册

    最后,ActionScript 3的优化技巧也是学习的重点,如正确使用垃圾回收机制,避免不必要的内存泄漏,以及利用早期绑定和优化代码结构来提高性能。 总的来说,《Flash AS3 手册》包含了从基础到高级的所有内容,无论你...

    AS3性能测试

    3. **内存管理**:AS3使用垃圾回收机制管理内存,但过度的内存分配和释放可能导致性能下降。测试可以帮助识别内存泄漏或不必要的资源消耗,从而调整代码以实现更高效的内存使用。 4. **事件处理**:AS3中的事件驱动...

    AS3过渡效果、源码

    此外,AS3还支持许多高级特性,如类型系统、错误处理、垃圾回收等,这些都是成为一名熟练的AS3开发者所必备的知识。通过深入研究这些源码,你可以进一步提升自己在AS3编程和动画制作方面的技能。不过,由于没有提供...

    flash as3 官方帮助文档 pdf

    14. **性能优化**:AS3允许开发者利用位运算、优化的循环结构和垃圾回收机制,提高程序运行效率。 通过深入学习这份官方文档,无论是初学者还是有经验的开发者,都能掌握ActionScript 3.0的精髓,从而在Flash平台上...

    flash actionscript3 as3 开发游戏 仿愤怒的小鸟.zip

    合理使用垃圾回收、减少不必要的计算、优化绘制和内存使用都是必要的。 压缩包中的"PigVSpig.swf"文件很可能是编译后的SWF文件,可以直接在Flash Player中运行查看游戏效果。而"AngryBirds_lj提取资源和源码后得到...

    flashas3 api使用手册

    AS3相较于之前的版本,进行了大量的语法改进和性能提升,包括类的完全支持、强类型系统和垃圾回收机制。AS3中的所有数据都是对象,这使得它更接近于传统的面向对象编程语言。基础知识点包括变量声明(var关键字)、...

    FLASH AS 3.0 3D螺旋相册

    AS3的事件模型、垃圾回收机制和优化的虚拟机都极大地提升了程序的性能和稳定性。 2. **3D图形处理**:在AS3中,可以使用“flash.display”库中的类,如“Sprite”和“Shape”,来创建基本的3D几何形状。通过矩阵...

    Flash AS3 工具性能输出窗口

    2. **内存管理**:AS3使用垃圾回收机制管理内存,但不当的内存分配和释放可能导致内存泄漏。性能窗口可能包含内存使用情况的图表,显示峰值和增长趋势,从而帮助检测内存问题。 3. **渲染效率**:在Flash环境中,...

    as3离线学习参考手册

    此外,了解如何优化代码性能,减少内存消耗,以及利用垃圾回收机制,对于开发高效应用不可或缺。 这份“AS3离线学习参考手册”的CHM文件可能包含了以上所有知识点的详细解释,包括示例代码、错误处理、最佳实践等,...

    AS3 AStar优化版.rar

    2. **内存管理**:优化了内存分配和复用,减少不必要的对象创建和垃圾回收,提高程序运行效率。 3. **代码重构**:通过精简代码和消除冗余,使得算法执行流程更加简洁,减少了不必要的计算和分支。 4. **启发式...

    Avm2虚拟机浅析与as3性能优化

    5. **垃圾回收管理**:合理控制对象的生命周期,及时释放不再使用的对象以触发垃圾回收机制。 #### 对AVM2进行扩充和改造 除了上述提到的AS3代码优化技巧之外,还可以考虑对AVM2本身进行扩展和改造,以适应特定的...

    AS+2.0与AS+3.0对照速查表

    - AS 3.0实现了自动垃圾回收,无需手动管理内存,而AS 2.0则需要开发者自行管理。 "AS 2.0与AS 3.0对照速查表.exe"文件可以帮助开发者快速查找两个版本间的语法差异,以便在从AS 2.0迁移到AS 3.0的过程中顺利过渡...

Global site tag (gtag.js) - Google Analytics