Apache flex 组件没有';不要把垃圾收集起来

Apache flex 组件没有';不要把垃圾收集起来,apache-flex,memory-leaks,flex4,Apache Flex,Memory Leaks,Flex4,我只是在Flash Profiler中查看我的应用程序时注意到一个奇怪的行为。当我单击标题窗口中的按钮时,标题窗口在被删除后不会被垃圾收集。我不知道为什么会这样 我创建了一个小示例应用程序,您可以自己尝试: 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/

我只是在Flash Profiler中查看我的应用程序时注意到一个奇怪的行为。当我单击标题窗口中的按钮时,标题窗口在被删除后不会被垃圾收集。我不知道为什么会这样

我创建了一个小示例应用程序,您可以自己尝试:

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>
<?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.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>
<?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。但是,当您单击“单击我!”并随后关闭ExampleView时,ExampleView将永远留在内存中


我无法在分析器中找到导致此行为的引用。我希望有人知道这个问题的解决方案,否则Flex会造成大量内存泄漏。

我可能错了,但MXML中添加的iirc EventListener总是使用强引用创建的,这将防止按钮被GC'加密


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

您可能会忘记的一件事是,垃圾收集不会在未引用的对象丢失最后一个引用时收集它们。通常GC只在您创建一些对象之后才会收集松散的实例,但即使如此,它是否会在那一刻收集也不明显。您可以在此处阅读更多信息:

或者看一下本演示文稿:




看看这个。如果您按下“强制GC”按钮几次,它将收集ExampleWindow。在执行某些操作的实际应用程序中,这种情况不需要调用System.gc()(事实上,调用它不是一种好的做法),但经过一段时间后,这些操作不仅在您完成时消失,而且在您完成时消失,Flash Player决定它需要清理。

看起来ExampleView没有被垃圾收集,因为在单击“单击我”时不知何故添加了一些EventListener。 避免这种情况的最好方法是 1.在createComplete事件中手动添加事件侦听器 2.删除closeHandler中的EventListener 3.从容器中移除按钮并将其设置为null


现在,ExampleView将被垃圾收集

起初,我怀疑也是这样。因此,正如您在示例中看到的,我删除了按钮事件处理程序。不过,每当我点击按钮时,标题窗口将不会被垃圾收集。此外,引用其父对象中的闭包的按钮不应该是问题。@gertschi:啊,对不起,不知何故,将第一个按钮误读为第二个按钮。谢谢你在closeHandler的提示。我仔细看了一下,发现从TitleWindow的close事件(或从窗口中触发的任何其他事件)中删除TitleWindow不会在单击“单击我”按钮时产生内存泄漏。通过单击应用程序控制栏中的附加按钮来删除标题窗口总是让GC也从内存中删除它。它肯定与容器子组件(如按钮或文本输入)有关。我在Adobe的bugtracker上创建了一个bug:。经过进一步测试,这种情况似乎只发生一次。因此,如果您执行这些步骤(打开窗口,单击“单击我”,关闭窗口)三次,则只有一个TitleWindow实例不会被垃圾收集。感谢链接。我已经知道了。为了确定,我又看了一眼。然而,我不认为GC忽略了这些实例,即使它们没有被引用。显然,TitleWindow中的组件(例如,通过单击“单击我”按钮)可以阻止TitleWindow的垃圾收集。我只是不明白为什么会发生这种事。你当然是对的。Flash Player的GC仅在必要时收集。然而,我确信在那里的某个地方有一个bug。看看我创建的bug。这里有一个简单的示例,演示了TextInput这样的子组件如何防止其父组件的垃圾收集。我刚刚测试了你在其中强制GC的方法,但没有任何帮助。无论如何,我会将此标记为答案,因为您提供了大量有用的信息/链接,希望我的错误报告不会像其他许多人一样被Adobe忽视。Adobe的bugtracker已经关闭。然而,这个问题现在可以在Apaches bugtracker中找到。