0

我有一个与 Spark Combo 框相关的简单、可重现的内存泄漏,但我确信这一定是我做错了,而不是 SDK 错误。

// Application.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">
    <s:layout>
        <s:VerticalLayout />
    </s:layout>
    <fx:Script>
        <![CDATA[
            import mx.events.FlexEvent;

            private var hasElement:Boolean;
            protected function toggleContainer():void
            {
                if (hasElement)
                {
                    button.setFocus();
                    comboBoxContainer.removeAllElements();
                    hasElement = false;
                } else {
                    var vew:ComboBoxView = new ComboBoxView();
                    comboBoxContainer.addElement(vew);
                    hasElement = true;
                }
            }
        ]]>
    </fx:Script>
    <s:Button id="button" label="Add container" click="toggleContainer()"  />
    <s:Group id="comboBoxContainer" />
</s:Application>


// ComboBoxView.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009" 
         xmlns:s="library://ns.adobe.com/flex/spark" 
         xmlns:mx="library://ns.adobe.com/flex/mx"
         >
    <s:ComboBox />
</s:VGroup>

当针对 Flex 4.1 编译时,这似乎会造成内存泄漏,其中 ComboBoxView 永远不会被 GC 处理——因为对 ComboBox 的持续引用。

这是分析器的输出: 在此处输入图像描述

重现步骤:

  • Application.mxml使用and创建一个项目ComboBoxView.mxml
  • 使用 Flex 4.1 编译项目
  • 使用分析器启动 Application.mxml
  • 创建内存快照
  • 单击按钮将视图添加到舞台
  • 再次单击该按钮以从舞台上移除视图
  • 运行垃圾收集器
  • 创建另一个内存快照
  • 查看两个内存快照之间的延迟对象

注意 - 当应用程序针对 Flex Hero 编译时不会发生这种情况。

看起来好像这是一个错误,但我无法相信 ComboBox 有内存泄漏——这肯定会在 4.1 发布之前修复吗?

我在这里做错了什么?为什么视图没有被 GC 处理?

更新 我已经对此进行了进一步调查,并认为问题在于 ComboBoxSkin 使用的 RichEditableText 组件存在问题。在此处查看详细信息: Spark 内存泄漏

4

2 回答 2

1

http://www.iampj.com/search/label/combobox%20memory%20leak

I have been having similar problems in flex 3

于 2011-06-07T12:35:36.487 回答
0

MXML 有时很棘手,因为您永远不知道幕后发生了什么(除非您使用 -keep 属性并查看)。

但是,在我看来,您永远不会取消 ComboBox 引用。移除一个容器的子节点与从内存中移除该实例不同。例如,在 Flextras 日历组件中,我们经常会随着月份的变化而从显示中删除日期。根据月份的不同,可能会显示 28 到 31 天之间的任何时间。但是,如果你在一个月有 31 天并切换到一个有 30 天的月份,那么我们不会清空那些额外的一天渲染器,我们只是将它们缓存在“unusedDays”数组中,然后我们为下一个做好准备月份切换的时间。

ListBase 类做的类似,我相信 Flex 4 甚至有一个名为 useVirtualLayout 的属性来控制这些东西如何保存在内存中。

我希望这不是一个太啰嗦或自我放纵的解释,我希望它是有道理的。

我认为您需要做一些事情来使 ComboBox 为空。我会尝试的第一件事是给 ComboBox 一个 ID:

<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009" 
         xmlns:s="library://ns.adobe.com/flex/spark" 
         xmlns:mx="library://ns.adobe.com/flex/mx"
         >
    <s:ComboBox id="myComboBox" />
</s:VGroup>

然后在您的 ActionScript 代码中,创建 ComboBoxView 的一个实例(不是本地函数):

protected var vew:ComboBoxView = new ComboBoxView();

然后像这样处理垃圾收集:

        if (hasElement)
        {
            button.setFocus();
            comboBoxContainer.removeAllElements();
            comboBoxContainer.myComboBox = null;
            comboBoxContainer = null;
            hasElement = false;
        } else {
            var vew:ComboBoxView = new ComboBoxView();
            comboBoxContainer.addElement(vew);
            hasElement = true;
        }
    }

我自己没有进行测试,我的直觉是并非所有这些步骤都是必需的;但我怀疑我的方法可能是正确的。

于 2011-02-12T03:31:25.507 回答