组件不会收集垃圾

时间:2010-10-18 08:46:28

标签: flex memory-leaks flex4

我在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会造成大量内存泄漏。

3 个答案:

答案 0 :(得分:2)

我可能错了,但是在MXML中添加的iirc EventListeners总是使用强引用创建,这会阻止Button被GC控制。

您是否尝试手动添加EventListener并将其设置为弱引用?如果您查看调试器中的EventListeners列表,如果添加了弱引用,您应该会看到类似WeakMethodClosure的内容。

答案 1 :(得分:1)

您可能忘记的一件事是,垃圾收集在它们松开最后一个引用时不会收集未引用的对象。通常情况下,只有在创建了一些对象后,GC才会收集松散的实例,但即使它在那一刻也不会显而易见。你可以在这里阅读更多相关信息:

About garbage collection

或者看一下这个演示文稿: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