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


这会导致内存泄漏吗?

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”在上面的任何代码中都没有使用,所以我认为两者都会导致内存泄漏。


10769
2017-12-12 08:26


起源

此时也没有导致内存泄漏,因为您可能需要所有1000个动画片段都可以点击。只有当你完成了动画片段并且希望将它们从内存中删除时才会发生事件监听器问题。 Ascention的答案是正确的,但“会”这个词很重要。 - crooksy88
在座的每个人,我都会纠正。我再也不会相信adobe文档了。看到我更新的答案。我目前的答案是错的。


答案:


你的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);

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

设置 将useWeakReference 如果您向舞台添加Eventlistener,则为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作为侦听器函数时,内存消耗将每帧上升。


6
2017-12-13 13:46



我上面提供的测试代码不断在每帧上创建1000个动画片段。如果有内存泄漏,内存消耗 具有 成长,因为所有这些物体都不会被收集。但他们是。通过将Movieclips添加为舞台的侦听器,会发生内存泄漏。引用始终是从调度程序到侦听器,而不是相反。因此,如果没有对调度员的引用,无论它有多少听众,它都将被销毁。 - Malyngo
你是100%正确的先生。我有所纠正。我用更多信息更新了我的答案。自上次阅读文档以来,adobe似乎添加了新信息。我还要求将我的答案标记为不正确并给予您信用。
添加ENTER_FRAME事件有什么意义。循环不够吗? - Vishwas G
@Vishwas Gagrani循环将创建1000个Movieclips,然后不会再发生任何事情。如果存在内存泄漏,那些1000个剪辑将不会被垃圾收集,但它们也可能没有GCed,因为没有必要,因为内存不再增长。通过使用ENTER_FRAME事件并在每个帧上创建越来越多的动画片段,我确保利用内存泄漏。如果有,则内存消耗将增长和增长。如果没有,GC将收集这些动画片段并处理它们,使内存使用量保持不变。 - Malyngo


更新,正确答案

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

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

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

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

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

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

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

文章摘要:

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

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


6
2017-12-12 08:28





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

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

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


1
2017-12-12 08:32



“没有阻止范围”是错误的。如果你的意思是说范围与内存分配和解除分配无关,这是一个不同的故事,但简单地说没有块范围本身是错误的。
我实际上只要你不将一个函数计为块作用域并将它作为一个范围将其视为一个范围,我就会说它是真的。 (这在技术上也是如此)。 - WORMSS
我想JNissi想说的是,AS3使用变量提升,因此在循环内部或外部声明变量具有相同的效果;) - Patrick