守望者--AIR技术交流

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: ANE FlasCC 炼金术
查看: 2849|回复: 2
打印 上一主题 下一主题

[ActionScript] AS3垃圾回收整理

[复制链接]
  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    跳转到指定楼层
    楼主
    发表于 2015-1-10 20:22:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    来源页面:http://www.adobe.com/devnet/actionscript/learning/as3-fundamentals/garbage-collection.html
    原标题:Garbage collection internals for Flash Player and Adobe AIR
    原作者:Michelle Yaiser
    翻译者:-




    所有应用程序都要管理内存。应用程序的内存管理包括用于确定何时分配内存,分配多少内存,何时将内容放入回收站,以及何时清空回收站的准则。MMgc是Flash Player用于几乎所有内存分配工作的通用内存管理器。理解MMgc如何管理内存是优化您的代码和您应用程序的性能的一个重要部分。

    垃圾收集器自动回收的内存被视为“受管理的内存”。垃圾收集器确定内存何时不再被应用程序使用并回收它。本文分析Flash Player 11和AIR 3中的内存分配、垃圾收集流程和新的pauseForGCIfCollectionImminent()API。

    内存分配

    Flash Player使用一个页面分配程序(GCheap)来从OD分配大块(几MB)的内存。Gcheap然后将大内存块分解为较小的4K页面,并根据需要将这些页面提供给垃圾收集(GC)内存管理器。


    图1. GCHeap从OS分配内存,将它分解为4K的页面,并将这些页面提供给GC。

    GC然后使用这些4K页面为系统中不大于2K的对象提供内存。


    图2. 4K页面由GC分配给小于2K的对象

    对于大于2K的对象(位图、视频、文件等),GCHeap向一个大型的内存分配程序提供一组连续的4K内存块。
    当一个大内存块中几乎所有4K页面都分配了时,Flash Player运行垃圾收集来回收未使用的内存,然后GCHeap尝试从OS分配更多内存。换句话说,垃圾收集仅由内存分配触发。这一事实很重要,在测试和分析期间一定要记住,因为它意味着空闲应用程序的内存使用从不会改变。

    堆和堆栈

    堆是分配给在运行时创建或初始化的任何对象的内存。堆上的对象会一直存在到它们被垃圾收集。

    图3. 对象A存在于堆上。它由堆栈上的局部变量o引用。(图字:堆栈内存 堆内存)

    堆栈是存储在编译时定义的所有变量的内存。堆栈内存以一种顺序方式使用和重用。推送操作将一些内容添加到堆栈顶部。弹出操作从堆栈顶部删除一些内容。访问堆栈中间的内容的唯一方式是删除它上方的所有内容。

    局部方法变量、参数和关于在一个方法完成时返回到何处的信息,在方法运行时被推送到堆栈上。对堆栈的更改发生得非常快。对象的堆栈引用可能非常短暂。这些对象引用可能存在于堆栈上,但分配给这些对象的内存来自堆。


    图4. 局部变量在定义时被推送到堆栈上。关于在一个方法完成时返回何处的信息也推送到堆栈上。

    Flash运行时垃圾收集实现

    Flash Player和AIR结合使用延迟的引用计数和保守的标记并清除(mark-and-sweep)方法。

    延迟的引用计数

    在延迟的引用计数中,堆和堆栈引用之间存在区别。因为堆栈变化很快,并可能包含非常短暂的引用,所以引用计数不会在堆栈引用上执行。而在堆上为引用维护引用计数。


    图5. 对象会跟踪它们拥有多少个引用。

    堆上的每个对象会跟踪指向它的信息数量。每次您创建一个对象的引用,该对象的引用计数就会递增。当您删除一个引用时,该对象的引用计数会递减。如果对象的引用计数为0(没有任何信息指向它),它会被添加到零计数表(Zero Count Table,ZCT)中。当ZCT填满后,就会扫描堆栈以查找任何从堆栈到ZCT上的对象的引用。ZCT上任何没有堆栈引用的对象都会被删除。

    延迟引用计数的一个问题是循环引用。如果ObjectA和ObjectB彼此引用,而系统中没有其他对象指向它们,它们将从不会拥有一个零引用计数,因此从不满足使用引用计数进行垃圾收集的资格。这时可以使用“标记并清除”的垃圾收集方法。


    图6. Object A和Object B彼此引用,但没有其他引用。

    标记/清除

    在Flash Player或AIR中运行的应用程序具有多个GCRoot。您可以将GCRoot视为一个树的一部分,它将应用程序的对象当作树枝。舞台是一个GCRoot。加载程序是GCRoot。某些菜单是GCRoot。让在供应用程序使用的每个对象可从应用程序内的一个GCRoot访问。GCRoot从不会被垃圾收集。

    应用程序中的每个对象有一个“标记位”。当垃圾收集的标记阶段开始时,所有这些标记位会被清除。MMgc会跟踪应用程序中的所有GCRoot。垃圾收集器首先从这些根开始,跟踪每个对象并为它到达的每个对象设置标记位。任何不再能够从任何根到达的对象也不再能够从应用程序的任何地方到达——它的标记位不会在标记阶段设置。收集器完成对它找到的所有对象进行标记之后,就会开始清除阶段。任何没有设置标记位的对象都会被销毁,它的内存会被回收。


    图7. 一个循环引用中的对象没有被标记。

    图7显示,每个可从Gcroot到达的对象都设置了自己的标记位(蓝色)。一个循环引用中的两个对象(ObjectA和ObjectB)不可从GCRoot到达。它们的标记位将不会设置。因此,即使它们没有零引用计数,这两个对象也会被垃圾收集。

    弱引用

    Flash Player也可以维持对某些类型的对象的“弱引用”。弱引用是一种对垃圾收集器的正常跟踪过程(跟随所有根来查找可到达的对象的过程)不可见的引用。

    当您实例化一个新字典时,可以表明您希望它与字典的键建立较弱的关联。

    1. var d:Dictionary = new Dictionary( true );
    2. d[ someObject ] = someValue;
    复制代码


    您也可以在添加事件监听器时,将addEventListener()的函数useWeakReference参数设置为true。

    1. obj.addEventListener( "type", handler, false, 0, true );
    复制代码


    在这两种情况下,您都会要求Flash Player在两个对象之间建立引用,但以一种较弱的方式保持该引用。具体来讲,这意味着这个具体的引用在标记期间不会被跟随。


    图8. 若引用在标记期间不会被跟踪。

    在这种情况下,到Object B的唯一路径是弱的。在跟踪期间将不会经过它,因此Object B不会被标记,并会被收集。但是,如果还有另一个到Object B的强路径,Object B将被标记并被持久化。


    图9. 具有强引用的对象将在跟踪期间被找到并标记。

    您应该始终清理未使用的引用,从字典删除未使用的项,以及使用removeEventListener()。但是,有时清理未使用的引用不切实际或无法做到。比如在您的类在您不知情的情况下实例化和销毁时——项渲染器就是通过这种方式使用的。在这些情况下,维持对象的若引用将允许Flash Player最终删除它们并回收内存。

    保守收集

    MMgc被视为一种保守的标记/清除收集器。MMgc无法确定内存中的某些值是对象指针(内存地址)还是数字值。为了避免意外地收集值可能指向的对象,MMgc假设每个值都可以是一个指针。因此,一些没有实际被指向的对象将从不被收集,将被视为一种内存泄漏。尽管您希望最小化内存泄漏以优化性能,但由保守的GC所导致的偶然泄漏可能是随机的,不会随时间增长,并且对应用程序性能的影响比开发人员导致的泄漏小得多。

    增量收集

    不幸的是,垃圾收集可导致Flash Player在收集过程完成时定期暂停。这种暂停与应用程序当前运行的内存量成正比。它可能比希望的时间更长,在一些程序中可以察觉到。

    标记阶段是垃圾收集过程中最消耗时间的部分。由于此事实,标记过程使用一个动作队列和一个3色算法增量化了。该队列在标记增量之间维护标记状态。

    表1. 3色算法
    黑色对象已标记,不再位于队列中。
    灰色对象位于队列中,还未被标记。
    白色对象既未标记也不在队列中。


    在标记阶段的开始,所以GCRoot被推送到队列中并变为灰色。


    图10. GCRoot在推送到工作队列中时变成灰色。

    随着标记过程的继续,标记的对象变为灰色,并从工作队列删除。


    图11. 标记的对象是黑色的,不再在工作队列中。

    此过程会正常继续进行,直到将一个新对象(白色)添加到一个黑色对象上。当发生此情况时,白色对象从不会设置它的标记位,因为它们的GCRoot已标记。不设置它们的标记位,它们将在清除阶段被垃圾收集。


    图12. 新对象被添加到以前标记的对象上。

    要预防此问题,可以在MMgc中使用一个白色边界来强制将任何添加到黑色对象上的白色对象立即添加到工作队列中。


    图13. 添加到以前标记的对象中的新对象被立即添加到工作队列中。

    通过使用工作队列和3色算法,可开始和停止标记阶段来帮助避免长时间、意外的垃圾收集暂停。

    迫近度

    标记阶段可能是垃圾收集中最耗时的部分,但实际上清空回收站(重新分配空闲内存)也比较耗时。重新分配还可能导致应用程序暂停。垃圾收集器离标记阶段的完成和清除(重新分配)阶段的开始的时间称为“迫近度(imminence)”


    图14. 迫近度(图字:标记 暂停、迫近度增长)

    1. public static function pauseForGCIfCollectionImminent(imminence:Number = 0.75):void
    复制代码


    是Flash Player 11和AIR 3中的一个新方法,允许您通知垃圾收集器这是完成标记和执行收集的好时机(ActionScript参考文档中的API项)。计划在用户不会注意到时发生可能的暂停,这会带来更好的用户体验。例如,一个游戏可能在游戏中一个级别完成时调用此函数,进而减少在玩游戏期间发生暂停的机会。

    您传递给此方法的迫近度值用于与垃圾收集器处于标记阶段中的位置进行比较。如果您传递给它的值比垃圾收集器的迫近度值小,标记和清除将同步完成并导致应用程序暂停。垃圾收集器必须处于该过程的25%以上,才能响应这个暂停以进行收集的请求。传递一个较小的值(但大于0.25)很可能会强制执行收集,导致应用程序暂停。传递一个较大的值将告诉垃圾收集器只有在即将暂停时完成收集。

    延伸阅读
    理解内存管理和垃圾收集在Flash Player和AIR中的工作原理,将有助于您优化您的代码并开发更高性能的应用程序。请查阅Michael Labriola介绍垃圾收集的演示Talking Trash。阅读Christian Cantrell的Providing Hints to the Garbage Collector in AIR 3。您也可以阅读详细的MMgc讨论,其中包含对底层C++代码的描述。

    查看原文:Garbage collection internals for Flash Player and Adobe AIR

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
    收藏收藏 分享分享 支持支持 反对反对 微信
    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    沙发
     楼主| 发表于 2015-1-10 20:25:11 | 只看该作者
    一、内存泄漏
    指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费(百度搜的资料)。这段话是什么意思呢?打个比方吧,放牛人与一只牛,放牛人好比程序设计中的引用,牛好比对象。我们通过引用来控制对象,放牛人通过绳子牵着牛,当牛吃完草后应该牵它回家而不是放手让它走失。当我们失去对该对象(某块内存)的控制时就产生了“内存泄露”。

    二、垃圾回收
    简单点说不用的内存都是垃圾,而垃圾回收就是把没用的内存都回收以释放内存空间。
    AS3的垃圾回收主要有两种方法:“引用计数法”和“标识清除法”。

    引用计数法:当一个内存对象添加了一个引用的时候,这个计数器就加1,当删除一个内存对象的引用时,该计数器就减1。当FP判断计数器为0的时候表示这个对象已经没有引用了,没有引用就没办法控制他了,符合垃圾回收机制的条件。但有一种情况则会有所不同!当有多个对象互相引用的时候,所有的计数器始终为1,这时就出现了内存泄露的情况。举个例子:
    1. var a:Object = {}
    2. var b:Object = {foo:a};

    3. a.foo = b;

    4. a=null;

    5. b=null;
    复制代码

    上述代码中,所有对象的引用都被删除了。没有任何办法在程序中再访问这两个对象了,但这两个对象的引用计数器都是1,因为它们相互引用。 即该两个内存块确实是没用了,但是垃圾回收机却不清理它。可想而知,这个办法在一般情况下还是不错的,但是遇到这种情况就不行了!于是要考虑第二种
    方法了。

    标识清除法: 这个方法在执行的时候会从FLASH的根对象也就是root开始到每一个引用的对象做标识。然后FLASH会遍历当前程序中的所有引用,发现没有标识的对象就清除。这样的话清除就准确了!但是会遇到一个问题。遍历是很消耗CPU的,虽然fp9通过调整迭代标识清除缩减对CPU的占用,但是消耗依然很大!所以采用了另外一种比较消极的处理方法!就是分段执行,每次执行一部分,然后偶尔执行一次。这样来减小CPU的消耗。所以我们通常知道,FP9、10的垃圾回收机是偶尔执行的!

    三、垃圾回收的函数方法
    1. System.disposeXML()
    2. BitmapData.dispose()
    3. Loader.unloadAndStop()
    4. System.gc() //这是一个最有用的函数,却只适用于调试版的FP

    5. removeChild()

    6. removeEventListener()
    复制代码

    设置引用为null
    System.totalMemory,返回值是内存占用字节数,这个跟内存回收没什么关系,只是用来查看内存占用,调试常用到
    ……

    以上函数都是垃圾回收会用到的方法,不过一般需要按具体情况具体去确定综合运用几个方法。这个需要你真正理解FP的内存回收机制才会懂得如何运用。

    (有部分内容参考了网上的一些文章,不能一一列举,望原作者见谅)

    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    板凳
     楼主| 发表于 2015-1-10 20:27:02 | 只看该作者
    ==================================================
    作者:绿色花园
    ==================================================

    以下内容来自:http://www.adobe.com/cn/devnet/flash/articles/flash-pragmatism-5-as3-gc.html
    GC 和内存泄露无关
    垃圾回收,这次是一个被无数人讨论过的传统话题。
    Action Script 使用的是和 Java 相似的内存管理机制,并不会即时回收废弃对象的内存,而是在特定时间统一执行一次 GC(Gabage Collection)操作来释放废弃对象的内存,避免了重复判断是否需要回收产生的性能问题。
    但要注意,这只是决定回收的时机,而不是回收的内容。这个延迟执行内存回收也就是个表面的现象,不管什么时候执行 GC,能够回收的内存最终都能回收,不能回收的肯定不能回收。唯一的影响是,因为回收是延迟执行的,你在查看内存的时候不能直观地看到因为一个对象被废弃而回收内存的过程,会产生迷惑。
    但这对于解决内存泄露是无关紧要的。
    内存泄露指的就是当你销毁了一个对象的时候,它占用的内存却无法被回收,这会导致可用内存越来越小最终溢出,在内存紧张的环境中将会造成系统崩溃。其原因多种多样,但一般都是开发者的疏忽所致,没有提供给系统足够的可以销毁对象的依据。
    执行 GC 虽然和内存泄露没有关系,但是如果不在测试前执行 GC,你将看不到当时实际的不可回收内存的量,而内存泄露就是指不可回收内存的数量的增加。因此,测试内存回收将离不开 GC 方法。没有使用 GC 方法的测试用例是没有意义的,因为这其中掺杂了偶然性(什么时候执行 GC)。不少荒谬的测试结果都是因为没有在正确的位置执行 GC 导致的。
    Flash Player 虽然没有开放发布状态的手动 gc,但调试版本是可以使用的,正好可以让我们测试。此外下面的 HACK 代码也可以在发布阶段触发 GC。
    1. 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),这里也符合属性相互引用的原则。但是事件判断起来的确要比属性麻烦,因为相互引用的情况很多。在这里可以分为三种情况:
      • 对自己监听自己的事件,这相当于用自己的属性保存自己引用,任何情况都不会阻碍自己被回收。
      • 对自己的子对象(属性或者 child)监听自己的事件。因为子对象本来就是自己在维持它的引用,那么即使它们会维持你的引用,也只会形成一个循环。一旦你和 stage 脱离了联系,子对象同样也会脱离联系,当然也无法妨碍你自己被回收了。除非子对象因为一些原因可以单独维持引用(诸如被保存在静态属性中),但这种情况很少见。
      • 对自己的父对象 (parent 或者 stage) 监听自己的事件。因为这使得你成为了父对象的一个属性,只要 parent 或者 stage 不被回收,那么自己就不会被回收。尤其是 stage,它肯定不会被回收。这种情况一般都会导致自己无法回收,是必须 removeEventListener 的。

    总得来说,就是务必注意对 stage,parent 的事件监听,其他情况一般都是不会妨碍回收的。而对 stage,parent 的监听大多都是各种鼠标,键盘事件。数量并不多,专门注意这里可以杜绝大部分因为事件造成的内存泄露。
    其实,内存泄露并不容易出现。按照普通的编程习惯,只有监听 stage 事件这种做法会造成意料之外的泄露,一般都是可以顺利回收的。这比每次都要手工回收内存要方便多了。
    这里只有 BitmapData 是例外。除了遵从上面的规则外,要回收它的内存,必须手动调用 dispose 方法,习惯自动回收的人会很累。务必注意,Bitmap 对象的 bitmapData 属性是需要手动销毁的,Loader 加载的位图是需要手动销毁的,当你用一个生成的位图作为位图填充绘制平铺的图像后,在销毁这个图像后也必须销毁这个位图(所以你必须一直保存位图的引用)。BitmapData 是32位的未经任何压缩的图像,随便一个体积都会非常大,不处理好它们的回收,一个 BitmapData 泄露就可以顶你数万个复杂对象的泄露。
    如果出现非常明显的内存泄露,大部分时候都是位图泄露。所以在研究上面的引用计数法和标记清除法以及 GC 之前,请先保证位图部分不出问题。


    弱引用时的例外
    弱引用会改变垃圾回收的规则。如果使用了弱引用,addEventListener 将不会影响对象回收,即使对 stage 添加监听,也不会导致自己被回收。但是这同时也是缺点,因为有的时候你就是希望用引用限制住对象的回收,使用弱引用会使得这个对象有时回收有时不回收。虽然极少出现,但一旦出现,这种不容易重现的错误是很难查出来的。因此我并不推荐使用弱引用。
    弱引用在 AVM2 中只有两处:
    • 一处是 addEventListener 的第5个属性,名为 userWeakReference,设置为 true,监听事件将不会影响对象回收。
    • 一处是 Dictionary 的构造函数参数,名为 weakKeys,设置为 true,当键为复杂对象时,即使 Dictionary 存在,键依然可以被回收。注意,这里说的是键,不是值,值是不享受弱引用待遇的。这个属性也写得也很明白,是 weakKeys。


    内存泄露的查找方法
    Flash Builder 提供了一个概要分析工具,可以帮助我们查找内存泄露。大多数情况都可以帮助我们解决问题。可以查看下面的文章:
    关键点在于,检测内存泄漏应该是“创建,取样,销毁,再创建,取样”,然后以两次取样的对比数据来观察泄露。因为对象在第一次创建时会有一些缓存数据,它们在设计上就不会随着对象销毁而回收的,比如类定义的缓存,比如皮肤。它们只会创建一次,和我们看到的泄露并不是一回事。


    必要时可以执行强制 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,也无伤大雅吧。


    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    
    关闭

    站长推荐上一条 /4 下一条

    QQ|手机版|Archiver|网站地图|小黑屋|守望者 ( 京ICP备14061876号

    GMT+8, 2024-4-20 01:57 , Processed in 0.053807 second(s), 33 queries .

    守望者AIR

    守望者AIR技术交流社区

    本站成立于 2014年12月31日

    快速回复 返回顶部 返回列表