如果一个对象在Flash中被垃圾收集,它引用的对象的引用计数器是否会自动递减?

时间:2011-06-20 21:04:25

标签: flash flex actionscript-3 garbage-collection

前几天我正在考虑使用Flash GC,并提出了一个关于引用计数如何在以下4个类场景中起作用的问题(假设GuiMain是电影的文档类):

package com.gui {     
import flash.display.MovieClip;         
public class GuiMain extends MovieClip {         
 private var button1Handle:Button1;         
 public function GuiMain() {             
  // constructor code             
  button1Handle = new Button1();             
  addChild(button1Handle);            
  killButton1();         
 }                 
 public function killButton1(){             
  removeChild(button1Handle);             
  button1Handle = null;         
 }     
}     
}



package com.gui {     
import fl.controls.Button;    
import flash.display.*;         
public class Button1 extends Sprite {         
 private var button2Handle:Button2;         
 private var tester:Test;         
 public function Button1() {             
  // constructor code            
  button2Handle = new Button2();             
  tester = new Test();         
 }     
}     
}



package com.gui {         
public class Button2 {         
 public function Button2() {             
  // constructor code         
 }     
}     
}


package com.gui {     
import flash.display.MovieClip;     
import flash.events.Event;             
public class Test extends MovieClip{         
 public function Test() {             
  // constructor code            
  addEventListener(Event.ENTER_FRAME, yellLoudly);         
 }                 
 public function yellLoudly(e:Event){                         
  trace("AAAH!!!");         
 }     
}     
}

当在Button1中创建Button2和Test实例时,我希望它们的引用计数器递增。问题是,当创建它们的Button1对象从显示列表中删除并消除时,它们的引用计数器会相应减少吗?我测试了这段代码,Test类中的事件监听器似乎关闭了,但这并不一定意味着它或Button2实例符合GC的条件。即使它们是,它可能只在Mark和Sweep下,这比基于参考计数的GC慢。

一个明显的解决方案是让Button1类从/ null中删除它所引用的引用的侦听器,当它被删除时,如下所示:

package com.gui {     
import fl.controls.Button;     
import flash.display.*;         
public class Button1 extends Sprite {         
 private var button2Handle:Button2;         
 private var tester:Test;         
 public function Button1() {             
  // constructor code             
  button2Handle = new Button2();             
  tester = new Test();         
 }                 
 public function destroyRefs(){                   
  button2Handle = null;                   
  tester.removeEventListener(Event.ENTER_FRAME, tester.yellLoudly);                   
  tester = null;            
 }     
}     
}

但是在一个真实的程序中,我可能正在处理来自不同类的同一对象的多个引用(通过传入构造函数中的原始引用),不会将一个类中的引用设置为null导致所有值的值对同一个对象的其他引用也变为null?那肯定是不可取的......

主要问题如下:当对Button1的唯一引用被清空时,它引用的所有对象是否会减少它们的引用计数器(立即或当Button1对象被垃圾收集时)?

另外,有没有办法通过Flash调试器查看实时存在的对象的所有实例和/或它们的引用计数值?像这样的详细分析器真的有助于解决这些问题......

感谢, CCJ

4 个答案:

答案 0 :(得分:3)

无耻的自我推销,但这可以帮助你:http://divillysausages.com/blog/tracking_memory_leaks_in_as3

答案 1 :(得分:0)

在引用计数方面我没有想到AS3。如果在Button1中创建的那些对象只能通过Button1访问,那么一旦您将Button1归零,它们就有资格获得GC。例外是事件监听器,你必须清理它们或者那些对象不会被清除。 Flash没有考虑任何对象正在侦听。

答案 2 :(得分:0)

此演示文稿http://onflex.org/ACDS/AS3TuningInsideAVM2JIT.pdf非常清楚地描述了如何在AVM2(运行AS3的虚拟机)中实现垃圾收集。

答案 3 :(得分:0)

噢,一个很好的问题:)

据我所知,Mark和Sweep仅用于引用计数事件监听器,因为它们是唯一可以拥有“弱听众”的人。其他一切都是直接记忆参考计数。从本质上讲,你最大的问题是清理事件监听器,但如果事件监听器在你的类中(听自己,或者它的孩子甚至是外部事件),如果在整个应用程序中取消引用对象,它们应该正确地进行GC操作(不要把它存放在其他地方。)

如果你让对象或属性公开可见,其他类可以引用它们,它可能会阻止你的类的GC(它实际上取决于它的引用方式和所有类)。唯一要解决的是尝试尽可能地封装(一个类处理它自己的解除引用;查看IDisposable)以便其他人无法引用并尝试遵循良好的编码实践(防止意大利面条代码)。