前几天我正在考虑使用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
答案 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)以便其他人无法引用并尝试遵循良好的编码实践(防止意大利面条代码)。