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

Vis*_*ani 11 flash actionscript-3

这会导致内存泄漏吗?

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

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

那怎么样?

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

"removeEventListener"在上面的任何代码中都没有使用,所以我认为两者都会导致内存泄漏.

小智 6

更新,正确答案

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

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

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

原始(错误)答案和(错误)信息遵循

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

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

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

文章摘要:

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

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

最佳实践解决方案:

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

再次更新

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


Mal*_*ngo 6

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

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

以下代码:

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

很快就会有你的监听器功能,因为它没有任何强大的参考.

如果你向舞台添加一个Eventlistener,将useWeakReference设置为true可能非常相关

stage.addEventListener(MouseEvent.CLICK, someObjectBelowIntheDisplayList.listenerFunction);
Run Code Online (Sandbox Code Playgroud)

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

someObjectBelowIntheDisplayList.addEventListener(MouseEvent.CLICK, stage.onClick)
Run Code Online (Sandbox Code Playgroud)

上面的代码不会让你的someObjectBelowIntheDisplayList保持活着状态.它有一个对stage的引用,但是stage没有得到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
{

}
Run Code Online (Sandbox Code Playgroud)

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