The*_*978 1 air garbage-collection actionscript-3 addeventlistener
在ADL中启动以下代码时,为什么方块继续旋转?
var square:Sprite = new Sprite();
square.graphics.beginFill(0xFF0000);
square.graphics.drawRect(-25, -25, 50, 50);
square.x = square.y = 100;
addChild(square);
addEventListener(Event.ENTER_FRAME, rotateSquare, false, 0, true);
function rotateSquare(evt:Event):void
{
square.rotation += 2;
}
System.gc();
Run Code Online (Sandbox Code Playgroud)
以下显示对象具有弱引用的ENTER_FRAME事件侦听器.但是,打电话:
removeChild(testInstance);
testInstance = null;
Run Code Online (Sandbox Code Playgroud)
不会停止ENTER_FRAME事件:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Test extends Sprite
{
private var square:Sprite;
public function Test()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(evt:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
square = new Sprite();
square.graphics.beginFill(0xFF0000);
square.graphics.drawRect(-25, -25, 50, 50);
square.x = square.y = 100;
addChild(square);
addEventListener(Event.ENTER_FRAME, rotateSquare, false, 0, true);
// //Current Solution - only works on display objects
// addEventListener(Event.REMOVED_FROM_STAGE, removeHandler);
}
private function rotateSquare(evt:Event):void
{
trace("square is rotating");
square.rotation += 2;
}
// private function removeHandler(evt:Event):void
// {
// removeEventListener(Event.REMOVED_FROM_STAGE, removeHandler);
// removeEventListener(Event.ENTER_FRAME, rotateSquare);
// }
}
}
Run Code Online (Sandbox Code Playgroud)
我添加了REMOVED_FROM_STAGE事件侦听器,但这只适用于显示对象.
这是ENTER_FRAME事件特有的问题吗?
关于您的更新,我认为您误解了GC的工作原理.基本想法很简单.
创建对象时,flash会在称为堆的存储中分配一些内存.返回对此对象的引用.此引用是您存储在变量中的内容.什么是参考?一种访问此对象的方法.将其视为对象的链接.
var foo:Bar = new Bar();
Run Code Online (Sandbox Code Playgroud)
现在,在某些语言中,在某些时候你必须释放为这个对象分配的内存,或者你有内存泄漏.
在GC环境中,这是自动完成的.当然,你需要一些规则.此规则因具体GC而异,但一般而言,您可以说GC确定如果对象不再可访问,则该对象是可收集的.这是有道理的,因为如果你无法到达某个对象,就无法使用它.你丢失了它的链接.所以,它被认为是垃圾,最终将被收集.
关于如何确定可达性的细节有所不同,但在闪存中它是参考计数和标记和扫描算法的混合.
(以下只是一个高级概述,细节可能不准确)
一种方法是引用计数:它既简单又快速,但并不适用于所有情况.基本上,每个对象都有一个引用计数.每次将此对象分配给变量(即存储对象的引用)时,引用计数都会递增.每次丢失此引用时(例如,将null清空),此计数将减少.如果计数达到0,则表示该对象无法访问,因此它是可收集的.
这在某些情况下工作正常,但没有其他情况.特别是当有交叉引用时.
var foo1:Bar = new Bar(); // let's call this object Bar_1
var foo2:Bar = new Bar(); // let's call this one Bar_2
// at this point, Bar_1 has reference count of 1 (foo1) and Bar_2 has a reference of 1 (foo2)
foo1.theOtherFoo = foo2;
// now Bar_2 has a RC of 2: foo2 and foo1.theOtherFoo
foo2.theOtherFoo = foo1;
// now Bar_1 has a RC of 2: foo1 and foo2.theOtherFoo
foo1 = null;
// foo1 no longer references Bar_1, so its RC is decremented.
foo2 = null;
// foo2 no longer references Bar_2, so its RC is decremented.
// but still both Bar_1 and Bar_2 have a RC of 1.
Run Code Online (Sandbox Code Playgroud)
如您所见,Bar_1和Bar_2的RC均为1,但无法访问.这是引用计数不起作用的情况之一.因为所有意图和目的,两个对象都无法访问,但不会被收集.
这就是为什么有标记/扫描算法的原因.从高层的角度来看,它的作用是遍历对象图,从一些根对象开始并分析其关系以确定对象是否可达.该算法将确定即使Bar_1和Bar_2的RC为1,它们也不可达,因此应被视为垃圾并在某个时刻收集.
事件,听众和调度员的工作方式相同.他们不是一个特例.当你这样做时:
function test():void {
foo1.addEventListener("someEvent",someHandler);
}
function someHandler(e:Event):void {
}
Run Code Online (Sandbox Code Playgroud)
它和做的一样:
function test():void {
foo1.someProperty = this;
}
Run Code Online (Sandbox Code Playgroud)
效果是foo1现在有一个引用this.您通常在完成后调用removeEventListener有两个原因:
1)你不再想要foo1参考this.2)你不再想要听"someEvent"事件了.
很多人坚持使用弱引用,因为他们认为那时你可以假装你不必打电话removeEventListener(这显然太难......).这是错的.removeEventListener做两件事,两件都很重要.如果您想停止接收某些事件的通知,您必须告诉调度员.这真的很简单.在我看来,在大多数情况下,弱引用是不必要的.有些人主张默认使用它们; 但根据我的经验,在实践中这对他们来说是一项糟糕的服务,因为它让人们更加困惑,鼓励他们编写草率的代码并给他们一种印象,你可以忽略这种语言的基本特征(这并不难拍手)工作.
现在,经过这个相当长的(但希望有建设性的)咆哮,让我们来看看你的代码:
你的精灵不会被收集,因为它有2个参考:
1)square变量2)阶段.
第一个遵循上面的规则.第二个也是如此,但初看起来可能并不那么明显.但是如果你想一下它就有意义了.当你这样做:
addChild(square);
Run Code Online (Sandbox Code Playgroud)
square被添加到Test实例中,然后又添加到实例中stage.将stage永远是活的,所以如果事情可以从到达stage,它的到达.只要square添加了遗骸stage,您就可以确定它不会被收集.
所以,如果你在某些时候做了Sean Thayne建议的话:
removeChild(square)
square = null;
Run Code Online (Sandbox Code Playgroud)
你的Sprite收藏.这并不影响你告诉你的Test对象你想在每次输入框架时被调用的事实.而这正是发生的事情.在你不告诉它之前你不想再接收这个事件(调用removeEventListener),它会给你回电.
| 归档时间: |
|
| 查看次数: |
364 次 |
| 最近记录: |