我在Flash Profiler中查看我的应用程序时发现了一个奇怪的行为。当我单击TitleWindow中的按钮时,TitleWindow在删除后不会收集垃圾。我不知道为什么会这样。
我已经创建了一个小示例应用程序,因此您可以自己尝试一下:
Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" pageTitle="Memory Leak (Spark)">
<fx:Script>
<![CDATA[
protected function openWindowBtn_clickHandler():void
{
removeAllElements();
addElement(new ExampleView());
}
]]>
</fx:Script>
<s:controlBarContent>
<s:Button label="Open Window" id="openWindowBtn" click="openWindowBtn_clickHandler()"/>
</s:controlBarContent>
</s:Application>
ExampleView.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%" title="Example View" close="closeHandler()">
<fx:Script>
<![CDATA[
import mx.core.IVisualElementContainer;
protected function closeHandler():void
{
var visualElementParent:IVisualElementContainer = parent as IVisualElementContainer;
if (visualElementParent)
visualElementParent.removeElement(this);
else
parent.removeChild(this);
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/>
</s:layout>
<s:Button id="doSomethingBtn" label="Click me!"/>
</s:TitleWindow>
单击“打开窗口”并关闭ExampleView而不单击“单击我!”按钮然后GC启动并删除ExampleView。但是,当您点击“Click me!”时然后关闭ExampleView,ExampleView永远保留在内存中。
我无法在Profiler中找到导致此行为的引用。我希望有人知道解决方案,否则Flex会造成大量内存泄漏。
答案 0 :(得分:2)
我可能错了,但是在MXML中添加的iirc EventListeners总是使用强引用创建,这会阻止Button被GC控制。
您是否尝试手动添加EventListener并将其设置为弱引用?如果您查看调试器中的EventListeners列表,如果添加了弱引用,您应该会看到类似WeakMethodClosure
的内容。
答案 1 :(得分:1)
您可能忘记的一件事是,垃圾收集在它们松开最后一个引用时不会收集未引用的对象。通常情况下,只有在创建了一些对象后,GC才会收集松散的实例,但即使它在那一刻也不会显而易见。你可以在这里阅读更多相关信息:
或者看一下这个演示文稿:Garbage Collection - Alex Harui
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" pageTitle="Memory Leak (Spark)">
<fx:Script>
<![CDATA[
protected function openWindowBtn_clickHandler():void
{
removeAllElements();
addElement(new ExampleView());
}
protected function button1_clickHandler(event:MouseEvent):void
{
var o:Object = new Object();
System.gc();
}
]]>
</fx:Script>
<s:controlBarContent>
<s:Button label="Open Window" id="openWindowBtn" click="openWindowBtn_clickHandler()"/>
<s:Button label="Force GC" click="button1_clickHandler(event)"/>
</s:controlBarContent>
</s:Application>
看看这个。如果按几次“强制GC”按钮,它将收集ExampleWindow。在一个真实世界的应用程序中执行此操作而不需要调用System.gc()(事实上,调用它不是一个好习惯),但过了一段时间,所以事情不仅仅是当你消失时“完成了它们,当你完成它们时它们会消失,而Flash Player决定它需要清理。
答案 2 :(得分:0)
看起来ExampleView没有收集垃圾,因为在单击“Click Me”时会添加一些EventListener。 避免这种情况的最佳方法是 1.在createComplete事件中手动添加事件侦听器 2.在closeHandler中删除EventListener 3.从容器中删除按钮并将其设置为空
现在,ExampleView将被Garbage collcected