【问题标题】:Spark Combox Memory LeakSpark Combox 内存泄漏
【发布时间】:2011-02-12 01:34:30
【问题描述】:

我有一个与 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.mxmlComboBoxView.mxml 创建一个项目
  • 使用 Flex 4.1 编译项目
  • 使用分析器启动 Application.mxml
  • 创建内存快照
  • 单击按钮将视图添加到舞台
  • 再次单击该按钮可从舞台上移除视图
  • 运行垃圾收集器
  • 创建另一个内存快照
  • 查看两个内存快照之间的延迟对象

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

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

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

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

【问题讨论】:

    标签: apache-flex memory-leaks flex4 flex-spark


    【解决方案1】:

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

    我在 flex 3 中也遇到过类似的问题

    【讨论】:

      【解决方案2】:

      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;
              }
          }
      

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

      【讨论】:

      • 我测试了类似的方法。清空 ComboBox 允许父级被 GC,但 ComboBox 仍然存在。请注意,GC Root 的路径不是通过父级,而是通过 ComboBox 的子级(在本例中为 TLF 下级)。因此,将其从父级中移除并不使其符合垃圾回收条件。
      • 硬引用不会有什么不同,因为整个 ComboBoxView 都从显示列表中删除了。如果不仅仅是 GC 的不确定性和不愿行动,那肯定是 SDK somewhere 中的一个错误。如果您多次切换容器,并且只有一个 ComboBox 实例“泄漏”,那么这并不是真正的泄漏,只是 GC 懒惰。
      • @Marty Pitt 您在为 ComboBox 使用自定义渲染器吗?根据您发布的代码,答案是否定的;但我想我会澄清的。我已经解决了一些与 Flextras 客户端有关的内存问题,只需让他们重写他们的 itemRenderers [通常只需要删除数据绑定]。
      • @Flextras:不。该问题可以通过完全没有自定义组件来重现 - 所有火花。事实上,我只是通过在舞台上添加一个组合框来重现这个问题。
      • @Sophistifunk - 只有当唯一挥之不去的引用是通过ComboBoxView 的父级引用舞台时,这才是正确的。如果 ComboBox 中的某些东西在另一个对象(例如,stage.addEventListener())上添加了对自身的引用,那么这将阻止 GC。我实际上认为问题在于 TLF 代码 - 请参阅更新了解详细信息。
      猜你喜欢
      • 2018-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-08
      • 2013-01-20
      • 2011-10-31
      • 2019-08-10
      • 2013-06-24
      相关资源
      最近更新 更多