这段代码会导致内存泄漏吗?

时间:2011-12-12 08:26:32

标签: flash actionscript-3

这会导致内存泄漏吗?

var mc:MovieClip ; //<<<<<<< OUTSIDE LOOP

for ( var i=0 ; i< 1000 ; i++)
{
   mc = new MovieClip() ;
   mc.addEventListener( MouseEvent.CLICK , onClick) ;
}

那怎么样?

for ( var i=0 ; i< 1000 ; i++)
{
  var mc:MovieClip ; //<<<<<<< INSIDE LOOP
   mc = new MovieClip() ;
   mc.addEventListener( MouseEvent.CLICK , onClick) ;
}

“removeEventListener”未在上述任何代码中使用,因此我认为两者都会导致内存泄漏。

3 个答案:

答案 0 :(得分:6)

更新,正确答案

我原来的答案是错的,我真诚地道歉。我将保留所有居高临下的评论和信息,以便羞​​耻可能永远提醒我永远不要相信任何Adobe再说一遍。目前的文档现在说:

“如果您不再需要事件侦听器,请通过调用removeEventListener()将其删除,否则可能会导致内存问题。事件侦听器不会自动从内存中删除,因为垃圾收集器不会删除侦听器 只要调度对象存在 (除非useWeakReference参数设置为true)。“

注意事件监听器是垃圾收集天气有弱参考或者没有,只要首先删除调度对象。因此,在这两种情况下,它们都不会导致内存泄漏。我要求OP取消检查我的答案是否正确,并给@Malyngo提供信用/正确答案+ upvotes。

原始(错误)答案和(错误)信息跟随

两者都会。绑定事件侦听器会创建对原始对象的强引用,因此垃圾收集器不会清除它。您需要显式删除事件侦听器或将它们指定为弱引用,这应该是addEventListener的参数之一。

对于那些认为听众不会阻止其他物品被垃圾收集的人

http://gingerbinger.com/2010/07/actionscript-3-0-events-the-myth-of-useweakreference/

文章摘要:

“想象一下,我们的玩家死了,我们希望他被清理。但是,事件监听器会创建从舞台到玩家的引用。舞台是最顶层的显示对象,并且始终可以访问。因此,当标记清除进程运行时,此事件侦听器允许垃圾收集器从阶段跳转到我们的播放器对象,即使我们已清除所有其他引用并将其从显示列表中删除。“

因此,至少有一种情况是单独的事件监听器(强绑定)可以阻止收集对象 < / p>

最佳实践解决方案:

1)将其从显示列表中删除 2)如果是MovieClip,请告诉它停止() 3)删除对象创建的所有事件侦听器 4)通过将父对象中的任何引用设置为null来清除它们。

再次更新

内存泄漏并不一定意味着您将看到应用程序内存不断增长。内存泄漏还可以简单地描述在应用程序应该被回收时分配并在应用程序的生命周期中持续存储的内存。像这个测试代码这样的东西不会很容易被发现。但是在一个多小时的游戏中让它发生N次,我向你保证它会显示。我曾经写过一次加密算法,我遇到了同样的情况。过了一会儿,我的应用程序开始以每秒10帧或更少的帧速度开始,因为VM已经吃掉了大量的内存,它实际上还没有使用它,但它还在管理它。

答案 1 :(得分:6)

你的1000个动画片段将引用你的onClick功能。不是相反。 因此,如果你质疑你的1000个动画片段是否会获得GC:如果他们没有任何其他参考,他们最终会这样做。

另一方面,影片剪辑中对onClick函数的引用将使该影片保持活动状态(以及它可能属于的对象)。如果这些MC有任何其他参考,将使他们活着。

以下代码:

mc.addEventListener(MouseEvent.CLICK , function(ev:Event):void{  trace("I am only a poor anonymous function");  }, false, 0, true);

很快就会有你的听众功能GCed,因为它没有任何强大的参考。

如果您向舞台添加Eventlistener,

useWeakReference 设置为true可能非常相关

stage.addEventListener(MouseEvent.CLICK, someObjectBelowIntheDisplayList.listenerFunction);

上面的代码将使Object与您的侦听器函数保持活动状态,即使它没有其他引用。

someObjectBelowIntheDisplayList.addEventListener(MouseEvent.CLICK, stage.onClick)

上述代码不会让您的 someObjectBelowIntheDisplayList 保持活动状态。它有一个对舞台的引用,但是舞台没有引用 someObjectBelowIntheDisplayList

编辑:请尝试以下代码:

import flash.display.MovieClip;
import flash.events.Event;

var mc:MovieClip ; //<<<<<<< OUTSIDE LOOP

function enterframe(ev:Event):void
{
    for ( var i=0 ; i< 1000 ; i++)
    {
       mc = new MovieClip() ;
       mc.onClick = function(ev:Event){};
       // Use one of the following lines, comment out the other one
       //mc.addEventListener( MouseEvent.CLICK , onClick) ; // no memory leak
       stage.addEventListener(MouseEvent.CLICK, mc.onClick); // memory will rise up and up
    }
}

this.addEventListener(Event.ENTER_FRAME, enterframe);

function onClick(ev:Event):void
{

}

这段代码明确支持我所说的:使用mc.addEventListener将获取内存消耗。它将在我的系统上保持大约20MB。 当使用带有stage.addEventListener的行并使用mc.onClick作为侦听器函数时,内存消耗将每帧上升。

答案 2 :(得分:1)

两个示例都是相同的,因为actionscript基于ecmascript 3,它没有块范围。

编辑:让我更具体一点:没有块范围,但ActionScript中有函​​数范围。

与内存泄漏一样,对象将留在内存中。

相关问题